mirror of
https://github.com/asticode/go-astiav.git
synced 2025-09-26 20:21:15 +08:00
Added format/codec context private data + options
This commit is contained in:
@@ -210,6 +210,11 @@ func (cc *CodecContext) SetPixelFormat(pixFmt PixelFormat) {
|
||||
cc.c.pix_fmt = C.enum_AVPixelFormat(pixFmt)
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVCodecContext.html#af3379123060ad8cc9c321c29af4f8360
|
||||
func (cc *CodecContext) PrivateData() *PrivateData {
|
||||
return newPrivateDataFromC(cc.c.priv_data)
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVCodecContext.html#a7abe7095de73df98df4895bf9e25fc6b
|
||||
func (cc *CodecContext) Profile() Profile {
|
||||
return Profile(cc.c.profile)
|
||||
|
@@ -35,6 +35,7 @@ func TestCodecContext(t *testing.T) {
|
||||
require.Equal(t, Level(13), cc1.Level())
|
||||
require.Equal(t, MediaTypeVideo, cc1.MediaType())
|
||||
require.Equal(t, PixelFormatYuv420P, cc1.PixelFormat())
|
||||
require.NotNil(t, cc1.PrivateData())
|
||||
require.Equal(t, ProfileH264ConstrainedBaseline, cc1.Profile())
|
||||
require.Equal(t, NewRational(1, 1), cc1.SampleAspectRatio())
|
||||
require.Equal(t, StrictStdComplianceNormal, cc1.StrictStdCompliance())
|
||||
|
20
flags.go
20
flags.go
@@ -245,6 +245,26 @@ func (fs IOFormatFlags) Del(f IOFormatFlag) IOFormatFlags {
|
||||
|
||||
func (fs IOFormatFlags) Has(f IOFormatFlag) bool { return astikit.BitFlags(fs).Has(uint64(f)) }
|
||||
|
||||
type OptionSearchFlags astikit.BitFlags
|
||||
|
||||
func NewOptionSearchFlags(fs ...OptionSearchFlag) OptionSearchFlags {
|
||||
o := OptionSearchFlags(0)
|
||||
for _, f := range fs {
|
||||
o = o.Add(f)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func (fs OptionSearchFlags) Add(f OptionSearchFlag) OptionSearchFlags {
|
||||
return OptionSearchFlags(astikit.BitFlags(fs).Add(uint64(f)))
|
||||
}
|
||||
|
||||
func (fs OptionSearchFlags) Del(f OptionSearchFlag) OptionSearchFlags {
|
||||
return OptionSearchFlags(astikit.BitFlags(fs).Del(uint64(f)))
|
||||
}
|
||||
|
||||
func (fs OptionSearchFlags) Has(f OptionSearchFlag) bool { return astikit.BitFlags(fs).Has(uint64(f)) }
|
||||
|
||||
type PacketFlags astikit.BitFlags
|
||||
|
||||
func NewPacketFlags(fs ...PacketFlag) PacketFlags {
|
||||
|
@@ -114,6 +114,15 @@ func TestIOFormatFlags(t *testing.T) {
|
||||
require.False(t, fs.Has(IOFormatFlag(2)))
|
||||
}
|
||||
|
||||
func TestOptionSearchFlags(t *testing.T) {
|
||||
fs := NewOptionSearchFlags(OptionSearchFlag(1))
|
||||
require.True(t, fs.Has(OptionSearchFlag(1)))
|
||||
fs = fs.Add(OptionSearchFlag(2))
|
||||
require.True(t, fs.Has(OptionSearchFlag(2)))
|
||||
fs = fs.Del(OptionSearchFlag(2))
|
||||
require.False(t, fs.Has(OptionSearchFlag(2)))
|
||||
}
|
||||
|
||||
func TestPacketFlags(t *testing.T) {
|
||||
fs := NewPacketFlags(PacketFlag(1))
|
||||
require.True(t, fs.Has(PacketFlag(1)))
|
||||
|
@@ -186,6 +186,11 @@ func (fc *FormatContext) SetPb(i *IOContext) {
|
||||
fc.c.pb = i.c
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVFormatContext.html#ac4c0777e54085af2f3f1b27130e2b21b
|
||||
func (fc *FormatContext) PrivateData() *PrivateData {
|
||||
return newPrivateDataFromC(fc.c.priv_data)
|
||||
}
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/structAVFormatContext.html#a2590129e00adfa726ab2033a10e905e9
|
||||
func (fc *FormatContext) StartTime() int64 {
|
||||
return int64(fc.c.start_time)
|
||||
|
@@ -24,6 +24,7 @@ func TestFormatContext(t *testing.T) {
|
||||
require.Equal(t, IOContextFlags(0), fc1.IOFlags())
|
||||
require.Equal(t, int64(0), fc1.MaxAnalyzeDuration())
|
||||
require.Equal(t, "isom", fc1.Metadata().Get("major_brand", nil, NewDictionaryFlags()).Value())
|
||||
require.NotNil(t, fc1.PrivateData())
|
||||
require.Equal(t, int64(0), fc1.StartTime())
|
||||
require.Equal(t, 2, fc1.NbStreams())
|
||||
require.Len(t, fc1.Streams(), 2)
|
||||
|
@@ -26,6 +26,7 @@ var list = []listItem{
|
||||
{Name: "FormatEvent"},
|
||||
{Name: "IOContext"},
|
||||
{Name: "IOFormat"},
|
||||
{Name: "OptionSearch"},
|
||||
{Name: "Packet"},
|
||||
{Name: "Seek"},
|
||||
{Name: "SoftwareScaleContext"},
|
||||
|
12
option.c
Normal file
12
option.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <libavutil/opt.h>
|
||||
|
||||
int astiavOptionGet(void *obj, const char *name, const char **value, int flags)
|
||||
{
|
||||
uint8_t *v = NULL;
|
||||
int ret = av_opt_get(obj, name, flags, &v);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
*value = (const char *)v;
|
||||
return 0;
|
||||
}
|
60
option.go
Normal file
60
option.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package astiav
|
||||
|
||||
//#include <libavutil/opt.h>
|
||||
//#include "option.h"
|
||||
import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
c unsafe.Pointer
|
||||
}
|
||||
|
||||
func newOptionsFromC(c unsafe.Pointer) *Options {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return &Options{c: c}
|
||||
}
|
||||
|
||||
type Option struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// https://www.ffmpeg.org/doxygen/7.0/group__opt__mng.html#gabc75970cd87d1bf47a4ff449470e9225
|
||||
func (os *Options) List() (list []Option) {
|
||||
var prev *C.AVOption
|
||||
for {
|
||||
o := C.av_opt_next(os.c, prev)
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
list = append(list, Option{Name: C.GoString(o.name)})
|
||||
prev = o
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.ffmpeg.org/doxygen/7.0/group__opt__set__funcs.html#ga5fd4b92bdf4f392a2847f711676a7537
|
||||
func (os *Options) Set(name, value string, f OptionSearchFlags) error {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
cvalue := C.CString(value)
|
||||
defer C.free(unsafe.Pointer(cvalue))
|
||||
return newError(C.av_opt_set(os.c, cname, cvalue, C.int(f)))
|
||||
}
|
||||
|
||||
// https://www.ffmpeg.org/doxygen/7.0/group__opt__get__funcs.html#gaf31144e60f9ce89dbe8cbea57a0b232c
|
||||
func (os *Options) Get(name string, f OptionSearchFlags) (string, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
var cvalue *C.char = nil
|
||||
if err := newError(C.astiavOptionGet(os.c, cname, &cvalue, C.int(f))); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if cvalue == nil {
|
||||
return "", nil
|
||||
}
|
||||
defer C.av_freep(unsafe.Pointer(&cvalue))
|
||||
return C.GoString(cvalue), nil
|
||||
}
|
1
option.h
Normal file
1
option.h
Normal file
@@ -0,0 +1 @@
|
||||
int astiavOptionGet(void *obj, const char *name, const char **value, int flags);
|
12
option_search_flag.go
Normal file
12
option_search_flag.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package astiav
|
||||
|
||||
//#include <libavutil/opt.h>
|
||||
import "C"
|
||||
|
||||
// https://ffmpeg.org/doxygen/7.0/group__opt__mng.html#ga25801ba4fc9b5313eb33ec84e082dd72
|
||||
type OptionSearchFlag int64
|
||||
|
||||
const (
|
||||
OptionSearchFlagChildren = CodecContextFlag(C.AV_OPT_SEARCH_CHILDREN)
|
||||
OptionSearchFlagFakeObject = CodecContextFlag(C.AV_OPT_SEARCH_FAKE_OBJ)
|
||||
)
|
28
option_test.go
Normal file
28
option_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package astiav
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestOption(t *testing.T) {
|
||||
fc, err := AllocOutputFormatContext(nil, "mp4", "")
|
||||
require.NoError(t, err)
|
||||
pd := fc.PrivateData()
|
||||
require.NotNil(t, pd)
|
||||
os := pd.Options()
|
||||
require.NotNil(t, os)
|
||||
require.Equal(t, []Option{{Name: "brand"}, {Name: "empty_hdlr_name"}, {Name: "encryption_key"}, {Name: "encryption_kid"}, {Name: "encryption_scheme"}, {Name: "frag_duration"}, {Name: "frag_interleave"}, {Name: "frag_size"}, {Name: "fragment_index"}, {Name: "iods_audio_profile"}, {Name: "iods_video_profile"}, {Name: "ism_lookahead"}, {Name: "movflags"}, {Name: "cmaf"}, {Name: "dash"}, {Name: "default_base_moof"}, {Name: "delay_moov"}, {Name: "disable_chpl"}, {Name: "empty_moov"}, {Name: "faststart"}, {Name: "frag_custom"}, {Name: "frag_discont"}, {Name: "frag_every_frame"}, {Name: "frag_keyframe"}, {Name: "global_sidx"}, {Name: "isml"}, {Name: "moov_size"}, {Name: "negative_cts_offsets"}, {Name: "omit_tfhd_offset"}, {Name: "prefer_icc"}, {Name: "rtphint"}, {Name: "separate_moof"}, {Name: "skip_sidx"}, {Name: "skip_trailer"}, {Name: "use_metadata_tags"}, {Name: "write_colr"}, {Name: "write_gama"}, {Name: "min_frag_duration"}, {Name: "mov_gamma"}, {Name: "movie_timescale"}, {Name: "rtpflags"}, {Name: "latm"}, {Name: "rfc2190"}, {Name: "skip_rtcp"}, {Name: "h264_mode0"}, {Name: "send_bye"}, {Name: "skip_iods"}, {Name: "use_editlist"}, {Name: "use_stream_ids_as_track_ids"}, {Name: "video_track_timescale"}, {Name: "write_btrt"}, {Name: "write_prft"}, {Name: "pts"}, {Name: "wallclock"}, {Name: "write_tmcd"}}, os.List())
|
||||
_, err = os.Get("invalid", NewOptionSearchFlags())
|
||||
require.Error(t, err)
|
||||
v, err := os.Get("brand", NewOptionSearchFlags())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "", v)
|
||||
require.Error(t, os.Set("invalid", "", NewOptionSearchFlags()))
|
||||
const brand = "test"
|
||||
require.NoError(t, os.Set("brand", brand, NewOptionSearchFlags()))
|
||||
v, err = os.Get("brand", NewOptionSearchFlags())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, brand, v)
|
||||
}
|
18
private_data.go
Normal file
18
private_data.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package astiav
|
||||
|
||||
import "unsafe"
|
||||
|
||||
type PrivateData struct {
|
||||
c unsafe.Pointer
|
||||
}
|
||||
|
||||
func newPrivateDataFromC(c unsafe.Pointer) *PrivateData {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return &PrivateData{c: c}
|
||||
}
|
||||
|
||||
func (pd *PrivateData) Options() *Options {
|
||||
return newOptionsFromC(pd.c)
|
||||
}
|
Reference in New Issue
Block a user