mirror of
https://github.com/asticode/go-astiav.git
synced 2025-10-05 00:02:45 +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")
|
b := []byte("test")
|
||||||
require.NoError(t, cp6.SetExtraData(b))
|
require.NoError(t, cp6.SetExtraData(b))
|
||||||
require.Equal(t, b, cp6.ExtraData())
|
require.Equal(t, b, cp6.ExtraData())
|
||||||
sd := cp6.SideData()
|
testPacketSideData(cp6.SideData(), t)
|
||||||
require.NoError(t, sd.Add(PacketSideDataTypeDisplaymatrix, b))
|
|
||||||
require.Equal(t, b, sd.Get(PacketSideDataTypeDisplaymatrix))
|
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ import (
|
|||||||
// https://ffmpeg.org/doxygen/7.0/group__lavu__video__display.html
|
// https://ffmpeg.org/doxygen/7.0/group__lavu__video__display.html
|
||||||
type DisplayMatrix [9]uint32
|
type DisplayMatrix [9]uint32
|
||||||
|
|
||||||
func NewDisplayMatrixFromBytes(b []byte) (m *DisplayMatrix, err error) {
|
func newDisplayMatrixFromBytes(b []byte) (m *DisplayMatrix, err error) {
|
||||||
// Check length
|
// Check length
|
||||||
if len(b) < 36 {
|
if len(b) < 36 {
|
||||||
err = fmt.Errorf("astiav: invalid length %d < 36", len(b))
|
err = fmt.Errorf("astiav: invalid length %d < 36", len(b))
|
||||||
@@ -35,7 +35,7 @@ func NewDisplayMatrixFromRotation(angle float64) *DisplayMatrix {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m DisplayMatrix) Bytes() []byte {
|
func (m DisplayMatrix) bytes() []byte {
|
||||||
b := make([]byte, 0, 36)
|
b := make([]byte, 0, 36)
|
||||||
for _, v := range m {
|
for _, v := range m {
|
||||||
b = binary.LittleEndian.AppendUint32(b, v)
|
b = binary.LittleEndian.AppendUint32(b, v)
|
||||||
|
@@ -7,17 +7,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestDisplayMatrix(t *testing.T) {
|
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)
|
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}
|
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.NoError(t, err)
|
||||||
require.Equal(t, DisplayMatrix{0x0, 0xffff0000, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x0, 0x40000000}, *dm)
|
require.Equal(t, DisplayMatrix{0x0, 0xffff0000, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x0, 0x40000000}, *dm)
|
||||||
require.Equal(t, -90.0, dm.Rotation())
|
require.Equal(t, -90.0, dm.Rotation())
|
||||||
require.Equal(t, b, dm.Bytes())
|
require.Equal(t, b, dm.bytes())
|
||||||
dm = NewDisplayMatrixFromRotation(-90)
|
dm = NewDisplayMatrixFromRotation(-90)
|
||||||
require.Equal(t, -90.0, dm.Rotation())
|
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.NoError(t, err)
|
||||||
require.Equal(t, DisplayMatrix{0x0, 0x10000, 0x0, 0xffff0000, 0x0, 0x0, 0x0, 0x0, 0x40000000}, *dm)
|
require.Equal(t, DisplayMatrix{0x0, 0x10000, 0x0, 0xffff0000, 0x0, 0x0, 0x0, 0x0, 0x40000000}, *dm)
|
||||||
require.Equal(t, 90.0, dm.Rotation())
|
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)
|
f.c.sample_rate = C.int(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://ffmpeg.org/doxygen/7.0/group__lavu__frame.html#gae05843b941b79e56b955674e581a8262
|
// https://ffmpeg.org/doxygen/7.0/structAVFrame.html#a44d40e03fe22a0511c9157dab22143ee
|
||||||
func (f *Frame) NewSideData(t FrameSideDataType, size uint64) *FrameSideData {
|
func (f *Frame) SideData() *FrameSideData {
|
||||||
return newFrameSideDataFromC(C.av_frame_new_side_data(f.c, (C.enum_AVFrameSideDataType)(t), C.size_t(size)))
|
return newFrameSideDataFromC(&f.c.side_data, &f.c.nb_side_data)
|
||||||
}
|
|
||||||
|
|
||||||
// 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#a1e71ce60cedd5f3b6811714a9f7f9e0a
|
// 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
|
package astiav
|
||||||
|
|
||||||
//#include <libavutil/frame.h>
|
//#include <libavutil/frame.h>
|
||||||
|
//#include "frame_side_data.h"
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://ffmpeg.org/doxygen/7.0/structAVFrameSideData.html
|
// https://ffmpeg.org/doxygen/7.0/structAVFrameSideData.html
|
||||||
|
// https://ffmpeg.org/doxygen/7.0/group__lavu__frame.html#gae01fa7e427274293aacdf2adc17076bc
|
||||||
type FrameSideData struct {
|
type FrameSideData struct {
|
||||||
c *C.AVFrameSideData
|
sd ***C.AVFrameSideData
|
||||||
|
size *C.int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFrameSideDataFromC(c *C.AVFrameSideData) *FrameSideData {
|
func newFrameSideDataFromC(sd ***C.AVFrameSideData, size *C.int) *FrameSideData {
|
||||||
if c == nil {
|
return &FrameSideData{
|
||||||
return nil
|
sd: sd,
|
||||||
|
size: size,
|
||||||
}
|
}
|
||||||
return &FrameSideData{c: c}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://ffmpeg.org/doxygen/7.0/structAVFrameSideData.html#a76937ad48652a5a0cc4bff65fc6c886e
|
// https://ffmpeg.org/doxygen/7.0/group__lavu__frame.html#ggae01fa7e427274293aacdf2adc17076bcaf525ec92d2c5a78d44950bc3f29972aa
|
||||||
func (d *FrameSideData) Data() []byte {
|
func (d *FrameSideData) RegionsOfInterest() *frameSideDataRegionsOfInterest {
|
||||||
return bytesFromC(func(size *C.size_t) *C.uint8_t {
|
return newFrameSideDataRegionsOfInterest(d)
|
||||||
*size = d.c.size
|
|
||||||
return d.c.data
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://ffmpeg.org/doxygen/7.0/structAVFrameSideData.html#a76937ad48652a5a0cc4bff65fc6c886e
|
type frameSideDataRegionsOfInterest struct {
|
||||||
func (d *FrameSideData) SetData(b []byte) {
|
d *FrameSideData
|
||||||
C.memcpy(unsafe.Pointer(d.c.data), unsafe.Pointer(&b[0]), C.size_t(math.Min(float64(len(b)), float64(d.c.size))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://ffmpeg.org/doxygen/7.0/structAVFrameSideData.html#a07ff3499827c124591ff4bae6f68eec0
|
func newFrameSideDataRegionsOfInterest(d *FrameSideData) *frameSideDataRegionsOfInterest {
|
||||||
func (d *FrameSideData) Type() FrameSideDataType {
|
return &frameSideDataRegionsOfInterest{d: d}
|
||||||
return FrameSideDataType(d.c._type)
|
}
|
||||||
|
|
||||||
|
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
|
package astiav
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"testing"
|
"testing"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
@@ -90,18 +89,7 @@ func TestFrame(t *testing.T) {
|
|||||||
f5 := AllocFrame()
|
f5 := AllocFrame()
|
||||||
require.NotNil(t, f5)
|
require.NotNil(t, f5)
|
||||||
defer f5.Free()
|
defer f5.Free()
|
||||||
sd := f5.NewSideData(FrameSideDataTypeAudioServiceType, 4)
|
testFrameSideData(f5.SideData(), t)
|
||||||
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())
|
|
||||||
|
|
||||||
f6 := AllocFrame()
|
f6 := AllocFrame()
|
||||||
require.NotNil(t, f6)
|
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/structAVPacketSideData.html
|
||||||
|
// https://ffmpeg.org/doxygen/7.0/group__lavc__packet__side__data.html#ga9a80bfcacc586b483a973272800edb97
|
||||||
type PacketSideData struct {
|
type PacketSideData struct {
|
||||||
sd **C.AVPacketSideData
|
sd **C.AVPacketSideData
|
||||||
size *C.int
|
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
|
// 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 {
|
if len(b) == 0 {
|
||||||
return nil
|
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 {
|
if sd == nil {
|
||||||
return errors.New("astiav: nil pointer")
|
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
|
// 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 {
|
return bytesFromC(func(size *C.size_t) *C.uint8_t {
|
||||||
if d.sd == nil || d.size == nil {
|
if d.sd == nil || d.size == nil {
|
||||||
return 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 {
|
if sd == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -6,11 +6,39 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"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) {
|
func TestPacketSideData(t *testing.T) {
|
||||||
cp := AllocCodecParameters()
|
cp := AllocCodecParameters()
|
||||||
defer cp.Free()
|
defer cp.Free()
|
||||||
b := []byte("test")
|
|
||||||
sd := cp.SideData()
|
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()
|
pkt5 := AllocPacket()
|
||||||
require.NotNil(t, pkt5)
|
require.NotNil(t, pkt5)
|
||||||
defer pkt5.Free()
|
defer pkt5.Free()
|
||||||
b = []byte{1, 2, 3, 4}
|
testPacketSideData(pkt5.SideData(), t)
|
||||||
sd := pkt5.SideData()
|
|
||||||
require.NoError(t, sd.Add(PacketSideDataTypeAudioServiceType, b))
|
|
||||||
require.Equal(t, b, sd.Get(PacketSideDataTypeAudioServiceType))
|
|
||||||
|
|
||||||
pkt6 := AllocPacket()
|
pkt6 := AllocPacket()
|
||||||
require.NotNil(t, pkt6)
|
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