diff --git a/format_context.go b/format_context.go index 84d6b54..3beb1d0 100644 --- a/format_context.go +++ b/format_context.go @@ -4,6 +4,7 @@ package astiav //#include import "C" import ( + "fmt" "math" "unsafe" ) @@ -345,3 +346,21 @@ func (fc *FormatContext) SDPCreate() (string, error) { return newError(C.av_sdp_create(&fccs[0], C.int(len(fccs)), buf, C.int(size))) }) } + +// https://ffmpeg.org/doxygen/7.0/avformat_8c.html#a8d4609a8f685ad894c1503ffd1b610b4 +func (fc *FormatContext) FindBestStream(mt MediaType, wantedStreamIndex, relatedStreamIndex int) (*Stream, *Codec, error) { + // Find best stream + var cCodec *C.AVCodec + ret := C.av_find_best_stream(fc.c, C.enum_AVMediaType(mt), C.int(wantedStreamIndex), C.int(relatedStreamIndex), &cCodec, 0) + if err := newError(ret); err != nil { + return nil, nil, err + } + + // Loop through streams + for _, s := range fc.Streams() { + if s.Index() == int(ret) { + return s, newCodecFromC(cCodec), nil + } + } + return nil, nil, fmt.Errorf("astiav: no stream with index %d", ret) +} diff --git a/format_context_test.go b/format_context_test.go index f816fe2..494108e 100644 --- a/format_context_test.go +++ b/format_context_test.go @@ -35,6 +35,16 @@ func TestFormatContext(t *testing.T) { require.NoError(t, err) require.Equal(t, "v=0\r\no=- 0 0 IN IP4 127.0.0.1\r\ns=Big Buck Bunny\r\nt=0 0\r\na=tool:libavformat 61.1.100\r\nm=video 0 RTP/AVP 96\r\nb=AS:441\r\na=rtpmap:96 H264/90000\r\na=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z0LADasgKDPz4CIAAAMAAgAAAwBhHihUkA==,aM48gA==; profile-level-id=42C00D\r\na=control:streamid=0\r\nm=audio 0 RTP/AVP 97\r\nb=AS:161\r\na=rtpmap:97 MPEG4-GENERIC/48000/2\r\na=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=1190\r\na=control:streamid=1\r\n", sdp) + _, _, err = fc1.FindBestStream(MediaTypeUnknown, -1, -1) + require.Error(t, err) + s2, c1, err := fc1.FindBestStream(MediaTypeVideo, -1, -1) + require.NoError(t, err) + require.Equal(t, s1.Index(), s2.Index()) + require.Equal(t, s1.CodecParameters().CodecID(), c1.ID()) + s2, c1, err = fc1.FindBestStream(MediaTypeAudio, 1, 0) + require.NoError(t, err) + require.Equal(t, 1, s2.Index()) + fc2, err := AllocOutputFormatContext(nil, "mp4", "") require.NoError(t, err) defer fc2.Free() @@ -43,20 +53,20 @@ func TestFormatContext(t *testing.T) { fc3 := AllocFormatContext() require.NotNil(t, fc3) defer fc3.Free() - c, err := OpenIOContext("testdata/video.mp4", NewIOContextFlags(IOContextFlagRead)) + io, err := OpenIOContext("testdata/video.mp4", NewIOContextFlags(IOContextFlagRead)) require.NoError(t, err) - defer c.Close() //nolint:errcheck - fc3.SetPb(c) + defer io.Close() //nolint:errcheck + fc3.SetPb(io) fc3.SetStrictStdCompliance(StrictStdComplianceExperimental) fc3.SetFlags(NewFormatContextFlags(FormatContextFlagAutoBsf)) require.NotNil(t, fc3.Pb()) require.Equal(t, StrictStdComplianceExperimental, fc3.StrictStdCompliance()) require.True(t, fc3.Flags().Has(FormatContextFlagAutoBsf)) - s2 := fc3.NewStream(nil) - require.NotNil(t, s2) s3 := fc3.NewStream(nil) require.NotNil(t, s3) - require.Equal(t, 1, s3.Index()) + s4 := fc3.NewStream(nil) + require.NotNil(t, s4) + require.Equal(t, 1, s4.Index()) d := NewDictionary() d.Set("k", "v", 0) diff --git a/time.go b/time.go index 2fab460..0eb1b79 100644 --- a/time.go +++ b/time.go @@ -20,3 +20,26 @@ var ( func RelativeTime() int64 { return int64(C.av_gettime_relative()) } + +type CompareTimestampsResult uint8 + +const ( + CompareTimestampsResultUndefined CompareTimestampsResult = iota + CompareTimestampsResultAEqualB + CompareTimestampsResultABeforeB + CompareTimestampsResultAAfterB +) + +// https://ffmpeg.org/doxygen/7.0/group__lavu__math.html#ga151744358fff630942b926e67e67c415 +func CompareTimestamps(a, b int64, timeBaseA, timeBaseB Rational) CompareTimestampsResult { + switch C.av_compare_ts(C.int64_t(a), timeBaseA.c, C.int64_t(b), timeBaseB.c) { + case C.int(-1): + return CompareTimestampsResultABeforeB + case C.int(0): + return CompareTimestampsResultAEqualB + case C.int(1): + return CompareTimestampsResultAAfterB + default: + return CompareTimestampsResultUndefined + } +} diff --git a/time_test.go b/time_test.go index 912c3f4..9de8928 100644 --- a/time_test.go +++ b/time_test.go @@ -9,3 +9,15 @@ import ( func TestTime(t *testing.T) { require.NotEqual(t, 0, RelativeTime()) } + +func TestCompareTimestamps(t *testing.T) { + a := int64(0) + timeBaseA := NewRational(1, 1) + b := int64(2) + timeBaseB := NewRational(1, 2) + require.Equal(t, CompareTimestampsResultABeforeB, CompareTimestamps(a, b, timeBaseA, timeBaseB)) + a = 1 + require.Equal(t, CompareTimestampsResultAEqualB, CompareTimestamps(a, b, timeBaseA, timeBaseB)) + a = 2 + require.Equal(t, CompareTimestampsResultAAfterB, CompareTimestamps(a, b, timeBaseA, timeBaseB)) +}