mirror of
https://github.com/asticode/go-astiav.git
synced 2025-09-26 20:21:15 +08:00
Refactored frame/packet side data + added regions of interest to frame side data
This commit is contained in:
@@ -99,7 +99,5 @@ func TestCodecParameters(t *testing.T) {
|
||||
b := []byte("test")
|
||||
require.NoError(t, cp6.SetExtraData(b))
|
||||
require.Equal(t, b, cp6.ExtraData())
|
||||
sd := cp6.SideData()
|
||||
require.NoError(t, sd.Add(PacketSideDataTypeDisplaymatrix, b))
|
||||
require.Equal(t, b, sd.Get(PacketSideDataTypeDisplaymatrix))
|
||||
testPacketSideData(cp6.SideData(), t)
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ import (
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavu__video__display.html
|
||||
type DisplayMatrix [9]uint32
|
||||
|
||||
func NewDisplayMatrixFromBytes(b []byte) (m *DisplayMatrix, err error) {
|
||||
func newDisplayMatrixFromBytes(b []byte) (m *DisplayMatrix, err error) {
|
||||
// Check length
|
||||
if len(b) < 36 {
|
||||
err = fmt.Errorf("astiav: invalid length %d < 36", len(b))
|
||||
@@ -35,7 +35,7 @@ func NewDisplayMatrixFromRotation(angle float64) *DisplayMatrix {
|
||||
return m
|
||||
}
|
||||
|
||||
func (m DisplayMatrix) Bytes() []byte {
|
||||
func (m DisplayMatrix) bytes() []byte {
|
||||
b := make([]byte, 0, 36)
|
||||
for _, v := range m {
|
||||
b = binary.LittleEndian.AppendUint32(b, v)
|
||||
|
@@ -7,17 +7,17 @@ import (
|
||||
)
|
||||
|
||||
func TestDisplayMatrix(t *testing.T) {
|
||||
_, err := NewDisplayMatrixFromBytes([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||
_, err := newDisplayMatrixFromBytes([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||
require.Error(t, err)
|
||||
b := []byte{0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64}
|
||||
dm, err := NewDisplayMatrixFromBytes(b)
|
||||
dm, err := newDisplayMatrixFromBytes(b)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, DisplayMatrix{0x0, 0xffff0000, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x0, 0x40000000}, *dm)
|
||||
require.Equal(t, -90.0, dm.Rotation())
|
||||
require.Equal(t, b, dm.Bytes())
|
||||
require.Equal(t, b, dm.bytes())
|
||||
dm = NewDisplayMatrixFromRotation(-90)
|
||||
require.Equal(t, -90.0, dm.Rotation())
|
||||
dm, err = NewDisplayMatrixFromBytes([]byte{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64})
|
||||
dm, err = newDisplayMatrixFromBytes([]byte{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, DisplayMatrix{0x0, 0x10000, 0x0, 0xffff0000, 0x0, 0x0, 0x0, 0x0, 0x40000000}, *dm)
|
||||
require.Equal(t, 90.0, dm.Rotation())
|
||||
|
11
frame.go
11
frame.go
@@ -239,14 +239,9 @@ func (f *Frame) SetSampleRate(r int) {
|
||||
f.c.sample_rate = C.int(r)
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavu__frame.html#gae05843b941b79e56b955674e581a8262
|
||||
func (f *Frame) NewSideData(t FrameSideDataType, size uint64) *FrameSideData {
|
||||
return newFrameSideDataFromC(C.av_frame_new_side_data(f.c, (C.enum_AVFrameSideDataType)(t), C.size_t(size)))
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavu__frame.html#gadec0efb470b1eead6a979333d9deca0c
|
||||
func (f *Frame) SideData(t FrameSideDataType) *FrameSideData {
|
||||
return newFrameSideDataFromC(C.av_frame_get_side_data(f.c, (C.enum_AVFrameSideDataType)(t)))
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVFrame.html#a44d40e03fe22a0511c9157dab22143ee
|
||||
func (f *Frame) SideData() *FrameSideData {
|
||||
return newFrameSideDataFromC(&f.c.side_data, &f.c.nb_side_data)
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVFrame.html#a1e71ce60cedd5f3b6811714a9f7f9e0a
|
||||
|
5
frame_side_data.c
Normal file
5
frame_side_data.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#include <libavutil/frame.h>
|
||||
|
||||
AVRegionOfInterest* astiavConvertRegionsOfInterestFrameSideData(AVFrameSideData *sd) {
|
||||
return (AVRegionOfInterest*)sd->data;
|
||||
}
|
@@ -1,38 +1,79 @@
|
||||
package astiav
|
||||
|
||||
//#include <libavutil/frame.h>
|
||||
//#include "frame_side_data.h"
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVFrameSideData.html
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavu__frame.html#gae01fa7e427274293aacdf2adc17076bc
|
||||
type FrameSideData struct {
|
||||
c *C.AVFrameSideData
|
||||
sd ***C.AVFrameSideData
|
||||
size *C.int
|
||||
}
|
||||
|
||||
func newFrameSideDataFromC(c *C.AVFrameSideData) *FrameSideData {
|
||||
if c == nil {
|
||||
return nil
|
||||
func newFrameSideDataFromC(sd ***C.AVFrameSideData, size *C.int) *FrameSideData {
|
||||
return &FrameSideData{
|
||||
sd: sd,
|
||||
size: size,
|
||||
}
|
||||
return &FrameSideData{c: c}
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVFrameSideData.html#a76937ad48652a5a0cc4bff65fc6c886e
|
||||
func (d *FrameSideData) Data() []byte {
|
||||
return bytesFromC(func(size *C.size_t) *C.uint8_t {
|
||||
*size = d.c.size
|
||||
return d.c.data
|
||||
})
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavu__frame.html#ggae01fa7e427274293aacdf2adc17076bcaf525ec92d2c5a78d44950bc3f29972aa
|
||||
func (d *FrameSideData) RegionsOfInterest() *frameSideDataRegionsOfInterest {
|
||||
return newFrameSideDataRegionsOfInterest(d)
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVFrameSideData.html#a76937ad48652a5a0cc4bff65fc6c886e
|
||||
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))))
|
||||
type frameSideDataRegionsOfInterest struct {
|
||||
d *FrameSideData
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVFrameSideData.html#a07ff3499827c124591ff4bae6f68eec0
|
||||
func (d *FrameSideData) Type() FrameSideDataType {
|
||||
return FrameSideDataType(d.c._type)
|
||||
func newFrameSideDataRegionsOfInterest(d *FrameSideData) *frameSideDataRegionsOfInterest {
|
||||
return &frameSideDataRegionsOfInterest{d: d}
|
||||
}
|
||||
|
||||
func (d *frameSideDataRegionsOfInterest) data(sd *C.AVFrameSideData) *[(math.MaxInt32 - 1) / C.sizeof_AVRegionOfInterest]C.AVRegionOfInterest {
|
||||
return (*[(math.MaxInt32 - 1) / C.sizeof_AVRegionOfInterest](C.AVRegionOfInterest))(unsafe.Pointer(C.astiavConvertRegionsOfInterestFrameSideData(sd)))
|
||||
}
|
||||
|
||||
func (d *frameSideDataRegionsOfInterest) Add(rois []RegionOfInterest) error {
|
||||
sd := C.av_frame_side_data_new(d.d.sd, d.d.size, C.AV_FRAME_DATA_REGIONS_OF_INTEREST, C.size_t(C.sizeof_AVRegionOfInterest*len(rois)), 0)
|
||||
if sd == nil {
|
||||
return errors.New("astiav: nil pointer")
|
||||
}
|
||||
|
||||
crois := d.data(sd)
|
||||
for i, roi := range rois {
|
||||
crois[i].bottom = C.int(roi.Bottom)
|
||||
crois[i].left = C.int(roi.Left)
|
||||
crois[i].qoffset = roi.QuantisationOffset.c
|
||||
crois[i].right = C.int(roi.Right)
|
||||
crois[i].self_size = C.sizeof_AVRegionOfInterest
|
||||
crois[i].top = C.int(roi.Top)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *frameSideDataRegionsOfInterest) Get() ([]RegionOfInterest, error) {
|
||||
sd := C.av_frame_side_data_get(*d.d.sd, *d.d.size, C.AV_FRAME_DATA_REGIONS_OF_INTEREST)
|
||||
if sd == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
crois := d.data(sd)
|
||||
rois := make([]RegionOfInterest, int(sd.size/C.sizeof_AVRegionOfInterest))
|
||||
for i := range rois {
|
||||
rois[i] = RegionOfInterest{
|
||||
Bottom: int(crois[i].bottom),
|
||||
Left: int(crois[i].left),
|
||||
QuantisationOffset: newRationalFromC(crois[i].qoffset),
|
||||
Right: int(crois[i].right),
|
||||
Top: int(crois[i].top),
|
||||
}
|
||||
}
|
||||
return rois, nil
|
||||
}
|
||||
|
3
frame_side_data.h
Normal file
3
frame_side_data.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#include <libavutil/frame.h>
|
||||
|
||||
AVRegionOfInterest* astiavConvertRegionsOfInterestFrameSideData(AVFrameSideData *sd);
|
61
frame_side_data_test.go
Normal file
61
frame_side_data_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package astiav
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func testFrameSideData(sd *FrameSideData, t *testing.T) {
|
||||
rois1 := []RegionOfInterest{
|
||||
{
|
||||
Bottom: 1,
|
||||
Left: 2,
|
||||
QuantisationOffset: NewRational(3, 4),
|
||||
Right: 5,
|
||||
Top: 6,
|
||||
},
|
||||
{
|
||||
Bottom: 7,
|
||||
Left: 8,
|
||||
QuantisationOffset: NewRational(9, 10),
|
||||
Right: 11,
|
||||
Top: 12,
|
||||
},
|
||||
}
|
||||
require.NoError(t, sd.RegionsOfInterest().Add(rois1))
|
||||
rois2, err := sd.RegionsOfInterest().Get()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, rois1, rois2)
|
||||
}
|
||||
|
||||
func TestFrameSideData(t *testing.T) {
|
||||
f := AllocFrame()
|
||||
require.NotNil(t, f)
|
||||
defer f.Free()
|
||||
sd := f.SideData()
|
||||
|
||||
rois1, err := sd.RegionsOfInterest().Get()
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, rois1)
|
||||
rois1 = []RegionOfInterest{
|
||||
{
|
||||
Bottom: 1,
|
||||
Left: 2,
|
||||
QuantisationOffset: NewRational(3, 4),
|
||||
Right: 5,
|
||||
Top: 6,
|
||||
},
|
||||
{
|
||||
Bottom: 7,
|
||||
Left: 8,
|
||||
QuantisationOffset: NewRational(9, 10),
|
||||
Right: 11,
|
||||
Top: 12,
|
||||
},
|
||||
}
|
||||
require.NoError(t, sd.RegionsOfInterest().Add(rois1))
|
||||
rois2, err := sd.RegionsOfInterest().Get()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, rois1, rois2)
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
package astiav
|
||||
|
||||
//#include <libavutil/frame.h>
|
||||
import "C"
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavu__frame.html#gae01fa7e427274293aacdf2adc17076bc
|
||||
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)
|
||||
)
|
@@ -1,7 +1,6 @@
|
||||
package astiav
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
@@ -90,18 +89,7 @@ func TestFrame(t *testing.T) {
|
||||
f5 := AllocFrame()
|
||||
require.NotNil(t, f5)
|
||||
defer f5.Free()
|
||||
sd := f5.NewSideData(FrameSideDataTypeAudioServiceType, 4)
|
||||
require.NotNil(t, sd)
|
||||
sd.SetData([]byte{1, 2, 3})
|
||||
sd = f5.SideData(FrameSideDataTypeAudioServiceType)
|
||||
require.NotNil(t, sd)
|
||||
require.Equal(t, FrameSideDataTypeAudioServiceType, sd.Type())
|
||||
require.True(t, bytes.HasPrefix(sd.Data(), []byte{1, 2, 3}))
|
||||
require.Len(t, sd.Data(), 4)
|
||||
sd.SetData([]byte{1, 2, 3, 4, 5})
|
||||
sd = f5.SideData(FrameSideDataTypeAudioServiceType)
|
||||
require.NotNil(t, sd)
|
||||
require.Equal(t, []byte{1, 2, 3, 4}, sd.Data())
|
||||
testFrameSideData(f5.SideData(), t)
|
||||
|
||||
f6 := AllocFrame()
|
||||
require.NotNil(t, f6)
|
||||
|
@@ -1,8 +0,0 @@
|
||||
#include <libavutil/intreadwrite.h>
|
||||
|
||||
uint32_t astiavRL32(uint8_t *i) {
|
||||
return AV_RL32(i);
|
||||
}
|
||||
uint32_t astiavRL32WithOffset(uint8_t *i, int o) {
|
||||
return AV_RL32(i+o);
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
package astiav
|
||||
|
||||
//#include "int_read_write.h"
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/avr32_2intreadwrite_8h.html#ace46e41b9bd6cac88fb7109ffd657f9a
|
||||
func RL32(i []byte) uint32 {
|
||||
if len(i) == 0 {
|
||||
return 0
|
||||
}
|
||||
return uint32(C.astiavRL32((*C.uint8_t)(unsafe.Pointer(&i[0]))))
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/avr32_2intreadwrite_8h.html#ace46e41b9bd6cac88fb7109ffd657f9a
|
||||
func RL32WithOffset(i []byte, offset uint) uint32 {
|
||||
if len(i) == 0 {
|
||||
return 0
|
||||
}
|
||||
return uint32(C.astiavRL32WithOffset((*C.uint8_t)(unsafe.Pointer(&i[0])), C.int(offset)))
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t astiavRL32(uint8_t *i);
|
||||
uint32_t astiavRL32WithOffset(uint8_t *i, int o);
|
@@ -1,15 +0,0 @@
|
||||
package astiav
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestIntReadWrite(t *testing.T) {
|
||||
is := []uint8{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
require.Equal(t, uint32(0), RL32([]byte{}))
|
||||
require.Equal(t, uint32(0x4030201), RL32(is))
|
||||
require.Equal(t, uint32(0), RL32WithOffset([]byte{}, 4))
|
||||
require.Equal(t, uint32(0x8070605), RL32WithOffset(is, 4))
|
||||
}
|
@@ -8,6 +8,7 @@ import (
|
||||
)
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVPacketSideData.html
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavc__packet__side__data.html#ga9a80bfcacc586b483a973272800edb97
|
||||
type PacketSideData struct {
|
||||
sd **C.AVPacketSideData
|
||||
size *C.int
|
||||
@@ -20,13 +21,63 @@ func newPacketSideDataFromC(sd **C.AVPacketSideData, size *C.int) *PacketSideDat
|
||||
}
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavc__packet__side__data.html#gga9a80bfcacc586b483a973272800edb97aab8c149a1e6c67aad340733becec87e1
|
||||
func (d *PacketSideData) DisplayMatrix() *packetSideDataDisplayMatrix {
|
||||
return newPacketSideDataDisplayMatrix(d)
|
||||
}
|
||||
|
||||
type packetSideDataDisplayMatrix struct {
|
||||
d *PacketSideData
|
||||
}
|
||||
|
||||
func newPacketSideDataDisplayMatrix(d *PacketSideData) *packetSideDataDisplayMatrix {
|
||||
return &packetSideDataDisplayMatrix{d: d}
|
||||
}
|
||||
|
||||
func (d *packetSideDataDisplayMatrix) Add(m *DisplayMatrix) error {
|
||||
return d.d.addBytes(C.AV_PKT_DATA_DISPLAYMATRIX, m.bytes())
|
||||
}
|
||||
|
||||
func (d *packetSideDataDisplayMatrix) Get() (*DisplayMatrix, error) {
|
||||
b := d.d.getBytes(C.AV_PKT_DATA_DISPLAYMATRIX)
|
||||
if len(b) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return newDisplayMatrixFromBytes(b)
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavc__packet__side__data.html#gga9a80bfcacc586b483a973272800edb97a2093332d8086d25a04942ede61007f6a
|
||||
func (d *PacketSideData) SkipSamples() *packetSideDataSkipSamples {
|
||||
return newPacketSideDataSkipSamples(d)
|
||||
}
|
||||
|
||||
type packetSideDataSkipSamples struct {
|
||||
d *PacketSideData
|
||||
}
|
||||
|
||||
func newPacketSideDataSkipSamples(d *PacketSideData) *packetSideDataSkipSamples {
|
||||
return &packetSideDataSkipSamples{d: d}
|
||||
}
|
||||
|
||||
func (d *packetSideDataSkipSamples) Add(ss *SkipSamples) error {
|
||||
return d.d.addBytes(C.AV_PKT_DATA_SKIP_SAMPLES, ss.bytes())
|
||||
}
|
||||
|
||||
func (d *packetSideDataSkipSamples) Get() (*SkipSamples, error) {
|
||||
b := d.d.getBytes(C.AV_PKT_DATA_SKIP_SAMPLES)
|
||||
if len(b) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return newSkipSamplesFromBytes(b)
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavc__packet__side__data.html#gad208a666db035802403ea994912a83db
|
||||
func (d *PacketSideData) Add(t PacketSideDataType, b []byte) error {
|
||||
func (d *PacketSideData) addBytes(t C.enum_AVPacketSideDataType, b []byte) error {
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
sd := C.av_packet_side_data_new(d.sd, d.size, (C.enum_AVPacketSideDataType)(t), C.size_t(len(b)), 0)
|
||||
sd := C.av_packet_side_data_new(d.sd, d.size, t, C.size_t(len(b)), 0)
|
||||
if sd == nil {
|
||||
return errors.New("astiav: nil pointer")
|
||||
}
|
||||
@@ -36,12 +87,12 @@ func (d *PacketSideData) Add(t PacketSideDataType, b []byte) error {
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavc__packet__side__data.html#ga61a3a0fba92a308208c8ab957472d23c
|
||||
func (d *PacketSideData) Get(t PacketSideDataType) []byte {
|
||||
func (d *PacketSideData) getBytes(t C.enum_AVPacketSideDataType) []byte {
|
||||
return bytesFromC(func(size *C.size_t) *C.uint8_t {
|
||||
if d.sd == nil || d.size == nil {
|
||||
return nil
|
||||
}
|
||||
sd := C.av_packet_side_data_get(*d.sd, *d.size, (C.enum_AVPacketSideDataType)(t))
|
||||
sd := C.av_packet_side_data_get(*d.sd, *d.size, t)
|
||||
if sd == nil {
|
||||
return nil
|
||||
}
|
||||
|
@@ -6,11 +6,39 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func testPacketSideData(sd *PacketSideData, t *testing.T) {
|
||||
m1 := NewDisplayMatrixFromRotation(90)
|
||||
require.NoError(t, sd.DisplayMatrix().Add(m1))
|
||||
m2, err := sd.DisplayMatrix().Get()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, m1.Rotation(), m2.Rotation())
|
||||
}
|
||||
|
||||
func TestPacketSideData(t *testing.T) {
|
||||
cp := AllocCodecParameters()
|
||||
defer cp.Free()
|
||||
b := []byte("test")
|
||||
sd := cp.SideData()
|
||||
require.NoError(t, sd.Add(PacketSideDataTypeDisplaymatrix, b))
|
||||
require.Equal(t, b, sd.Get(PacketSideDataTypeDisplaymatrix))
|
||||
|
||||
m1, err := sd.DisplayMatrix().Get()
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, m1)
|
||||
m1 = NewDisplayMatrixFromRotation(90)
|
||||
require.NoError(t, sd.DisplayMatrix().Add(m1))
|
||||
m2, err := sd.DisplayMatrix().Get()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, m1.Rotation(), m2.Rotation())
|
||||
|
||||
ss1, err := sd.SkipSamples().Get()
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, ss1)
|
||||
ss1 = &SkipSamples{
|
||||
ReasonEnd: 1,
|
||||
ReasonStart: 2,
|
||||
SkipEnd: 3,
|
||||
SkipStart: 4,
|
||||
}
|
||||
require.NoError(t, sd.SkipSamples().Add(ss1))
|
||||
ss2, err := sd.SkipSamples().Get()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ss1, ss2)
|
||||
}
|
||||
|
@@ -1,47 +0,0 @@
|
||||
package astiav
|
||||
|
||||
//#include <libavcodec/avcodec.h>
|
||||
import "C"
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavc__packet__side__data.html#ga9a80bfcacc586b483a973272800edb97
|
||||
type PacketSideDataType C.enum_AVPacketSideDataType
|
||||
|
||||
const (
|
||||
PacketSideDataTypeA53Cc = PacketSideDataType(C.AV_PKT_DATA_A53_CC)
|
||||
PacketSideDataTypeAfd = PacketSideDataType(C.AV_PKT_DATA_AFD)
|
||||
PacketSideDataTypeAudioServiceType = PacketSideDataType(C.AV_PKT_DATA_AUDIO_SERVICE_TYPE)
|
||||
PacketSideDataTypeContentLightLevel = PacketSideDataType(C.AV_PKT_DATA_CONTENT_LIGHT_LEVEL)
|
||||
PacketSideDataTypeCpbProperties = PacketSideDataType(C.AV_PKT_DATA_CPB_PROPERTIES)
|
||||
PacketSideDataTypeDisplaymatrix = PacketSideDataType(C.AV_PKT_DATA_DISPLAYMATRIX)
|
||||
PacketSideDataTypeEncryptionInfo = PacketSideDataType(C.AV_PKT_DATA_ENCRYPTION_INFO)
|
||||
PacketSideDataTypeEncryptionInitInfo = PacketSideDataType(C.AV_PKT_DATA_ENCRYPTION_INIT_INFO)
|
||||
PacketSideDataTypeFallbackTrack = PacketSideDataType(C.AV_PKT_DATA_FALLBACK_TRACK)
|
||||
PacketSideDataTypeH263MbInfo = PacketSideDataType(C.AV_PKT_DATA_H263_MB_INFO)
|
||||
PacketSideDataTypeJpDualmono = PacketSideDataType(C.AV_PKT_DATA_JP_DUALMONO)
|
||||
PacketSideDataTypeMasteringDisplayMetadata = PacketSideDataType(C.AV_PKT_DATA_MASTERING_DISPLAY_METADATA)
|
||||
PacketSideDataTypeMatroskaBlockadditional = PacketSideDataType(C.AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL)
|
||||
PacketSideDataTypeMetadataUpdate = PacketSideDataType(C.AV_PKT_DATA_METADATA_UPDATE)
|
||||
PacketSideDataTypeMpegtsStreamId = PacketSideDataType(C.AV_PKT_DATA_MPEGTS_STREAM_ID)
|
||||
PacketSideDataTypeNb = PacketSideDataType(C.AV_PKT_DATA_NB)
|
||||
PacketSideDataTypeNewExtradata = PacketSideDataType(C.AV_PKT_DATA_NEW_EXTRADATA)
|
||||
PacketSideDataTypePalette = PacketSideDataType(C.AV_PKT_DATA_PALETTE)
|
||||
PacketSideDataTypeParamChange = PacketSideDataType(C.AV_PKT_DATA_PARAM_CHANGE)
|
||||
PacketSideDataTypeQualityStats = PacketSideDataType(C.AV_PKT_DATA_QUALITY_STATS)
|
||||
PacketSideDataTypeReplaygain = PacketSideDataType(C.AV_PKT_DATA_REPLAYGAIN)
|
||||
PacketSideDataTypeSkipSamples = PacketSideDataType(C.AV_PKT_DATA_SKIP_SAMPLES)
|
||||
PacketSideDataTypeSpherical = PacketSideDataType(C.AV_PKT_DATA_SPHERICAL)
|
||||
PacketSideDataTypeStereo3D = PacketSideDataType(C.AV_PKT_DATA_STEREO3D)
|
||||
PacketSideDataTypeStringsMetadata = PacketSideDataType(C.AV_PKT_DATA_STRINGS_METADATA)
|
||||
PacketSideDataTypeSubtitlePosition = PacketSideDataType(C.AV_PKT_DATA_SUBTITLE_POSITION)
|
||||
PacketSideDataTypeWebvttIdentifier = PacketSideDataType(C.AV_PKT_DATA_WEBVTT_IDENTIFIER)
|
||||
PacketSideDataTypeWebvttSettings = PacketSideDataType(C.AV_PKT_DATA_WEBVTT_SETTINGS)
|
||||
)
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavc__packet__side__data.html#ga78c05e43a5d021eb10e63b28a541bce3
|
||||
func (t PacketSideDataType) Name() string {
|
||||
return C.GoString(C.av_packet_side_data_name((C.enum_AVPacketSideDataType)(t)))
|
||||
}
|
||||
|
||||
func (t PacketSideDataType) String() string {
|
||||
return t.Name()
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
package astiav
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPacketSideDataType(t *testing.T) {
|
||||
require.Equal(t, "Display Matrix", PacketSideDataTypeDisplaymatrix.Name())
|
||||
require.Equal(t, "Display Matrix", PacketSideDataTypeDisplaymatrix.String())
|
||||
}
|
@@ -74,10 +74,7 @@ func TestPacket(t *testing.T) {
|
||||
pkt5 := AllocPacket()
|
||||
require.NotNil(t, pkt5)
|
||||
defer pkt5.Free()
|
||||
b = []byte{1, 2, 3, 4}
|
||||
sd := pkt5.SideData()
|
||||
require.NoError(t, sd.Add(PacketSideDataTypeAudioServiceType, b))
|
||||
require.Equal(t, b, sd.Get(PacketSideDataTypeAudioServiceType))
|
||||
testPacketSideData(pkt5.SideData(), t)
|
||||
|
||||
pkt6 := AllocPacket()
|
||||
require.NotNil(t, pkt6)
|
||||
|
13
region_of_interest.go
Normal file
13
region_of_interest.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package astiav
|
||||
|
||||
//#include <libavutil/frame.h>
|
||||
import "C"
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVRegionOfInterest.html
|
||||
type RegionOfInterest struct {
|
||||
Bottom int
|
||||
Left int
|
||||
QuantisationOffset Rational
|
||||
Right int
|
||||
Top int
|
||||
}
|
34
skip_samples.go
Normal file
34
skip_samples.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package astiav
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavc__packet__side__data.html#gga9a80bfcacc586b483a973272800edb97a2093332d8086d25a04942ede61007f6a
|
||||
// https://ffmpeg.org/doxygen/7.0/group__lavu__frame.html#ggae01fa7e427274293aacdf2adc17076bca6b0b1ee4315f322922710f65d02a146b
|
||||
type SkipSamples struct {
|
||||
ReasonEnd uint8
|
||||
ReasonStart uint8
|
||||
SkipEnd uint32
|
||||
SkipStart uint32
|
||||
}
|
||||
|
||||
func newSkipSamplesFromBytes(b []byte) (*SkipSamples, error) {
|
||||
if len(b) < 10 {
|
||||
return nil, fmt.Errorf("astiav: invalid length %d < 10", len(b))
|
||||
}
|
||||
return &SkipSamples{
|
||||
ReasonEnd: b[9],
|
||||
ReasonStart: b[8],
|
||||
SkipEnd: binary.LittleEndian.Uint32(b[4:8]),
|
||||
SkipStart: binary.LittleEndian.Uint32(b[0:4]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ss *SkipSamples) bytes() (b []byte) {
|
||||
b = binary.LittleEndian.AppendUint32(b, ss.SkipStart)
|
||||
b = binary.LittleEndian.AppendUint32(b, ss.SkipEnd)
|
||||
b = append(b, ss.ReasonStart, ss.ReasonEnd)
|
||||
return b
|
||||
}
|
23
skip_samples_test.go
Normal file
23
skip_samples_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package astiav
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSkipSamples(t *testing.T) {
|
||||
_, err := newSkipSamplesFromBytes([]byte("123456789"))
|
||||
require.Error(t, err)
|
||||
ss1 := &SkipSamples{
|
||||
ReasonEnd: 1,
|
||||
ReasonStart: 2,
|
||||
SkipEnd: 3,
|
||||
SkipStart: 4,
|
||||
}
|
||||
b1 := ss1.bytes()
|
||||
require.Equal(t, []byte{0x4, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x2, 0x1}, b1)
|
||||
ss2, err := newSkipSamplesFromBytes(b1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ss1, ss2)
|
||||
}
|
Reference in New Issue
Block a user