Skip to content

Commit

Permalink
Added format context find best stream + compare timestamps
Browse files Browse the repository at this point in the history
  • Loading branch information
asticode committed Nov 23, 2024
1 parent 4f133cd commit c9d8c33
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 6 deletions.
19 changes: 19 additions & 0 deletions format_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package astiav
//#include <libavformat/avformat.h>
import "C"
import (
"fmt"
"math"
"unsafe"
)
Expand Down Expand Up @@ -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)
}
22 changes: 16 additions & 6 deletions format_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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)
Expand Down
23 changes: 23 additions & 0 deletions time.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
12 changes: 12 additions & 0 deletions time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}

0 comments on commit c9d8c33

Please sign in to comment.