Skip to content

Commit

Permalink
Merge pull request #36 from mutablelogic/ffmpeg61
Browse files Browse the repository at this point in the history
Fixed bug with resampling
  • Loading branch information
djthorpe authored Jul 31, 2024
2 parents df83a43 + 6d2f60d commit 60e56f3
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 11 deletions.
Binary file added etc/test/jfk.wav
Binary file not shown.
19 changes: 9 additions & 10 deletions pkg/ffmpeg/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,17 @@ func (d *Decoder) Close() error {
// Decode a packet into a set of frames to pass back to the
// DecoderFrameFn. If the packet is nil, then the decoder will
// flush any remaining frames.
// TODO: Optionally use the user defined packet function
// if they want to use AVParser
// TODO: The frame sent to DecoderFrameFn needs to have the
// correct timebase, etc set
// TODO: Optionally use the user defined packet function if they want to use AVParser
func (d *Decoder) decode(packet *ff.AVPacket, fn DecoderFrameFn) error {
if fn == nil {
return ErrBadParameter.With("DecoderFrameFn is nil")
}

// Set the timebase for the packet
if packet != nil {
packet.SetTimeBase(d.timeBase)
}

// Submit the packet to the decoder (nil packet will flush the decoder)
if err := ff.AVCodec_send_packet(d.codec, packet); err != nil {
return ErrInternalAppError.With("AVCodec_send_packet:", err)
Expand All @@ -142,6 +144,9 @@ func (d *Decoder) decode(packet *ff.AVPacket, fn DecoderFrameFn) error {
return ErrInternalAppError.With("AVCodec_receive_frame:", err)
}

// Set the timebase for the frame
d.frame.SetTimeBase(packet.TimeBase())

// Obtain the output frame. If a new frame is returned, it is
// managed by the rescaler/resizer and no need to unreference it
// later.
Expand All @@ -161,12 +166,6 @@ func (d *Decoder) decode(packet *ff.AVPacket, fn DecoderFrameFn) error {
continue
}

// Copy across the timebase and pts
// TODO
// fmt.Println("pts=", d.frame.Pts())
// (*ff.AVFrame)(dest).SetPts(d.frame.Pts())
// (*ff.AVFrame)(dest).SetTimeBase(d.timeBase)

// Pass back to the caller
if err := fn(d.stream, dest); errors.Is(err, io.EOF) {
// End early, return EOF
Expand Down
35 changes: 35 additions & 0 deletions pkg/ffmpeg/reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,38 @@ func Test_reader_005(t *testing.T) {
t.FailNow()
}
}

func Test_reader_006(t *testing.T) {
assert := assert.New(t)

// Read a file
r, err := os.Open("../../etc/test/jfk.wav")
if !assert.NoError(err) {
t.FailNow()
}
defer r.Close()

input, err := ffmpeg.NewReader(r)
if !assert.NoError(err) {
t.FailNow()
}
defer input.Close()

// Map function - only audio streams
mapfn := func(stream int, par *ffmpeg.Par) (*ffmpeg.Par, error) {
if par.Type() == media.AUDIO {
t.Logf("Stream %v[%d] => %v", par.Type(), stream, par)
return par, nil
}
return nil, nil
}

framefn := func(stream int, frame *ffmpeg.Frame) error {
t.Log("Got frame", frame)
return nil
}

if err := input.Decode(context.Background(), mapfn, framefn); !assert.NoError(err) {
t.FailNow()
}
}
2 changes: 1 addition & 1 deletion pkg/ffmpeg/resampler.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (r *resampler) Frame(src *Frame) (*Frame, error) {
}

// Check buffer
// TODO UGLY CODE ALERT
// TODO: UGLY CODE ALERT
if r.dest.NumSamples() < num_samples {
sample_fmt := r.dest.SampleFormat()
sample_rate := r.dest.SampleRate()
Expand Down
6 changes: 6 additions & 0 deletions sys/ffmpeg61/swresample_convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ func SWResample_get_out_samples(ctx *SWRContext, in_samples int) (int, error) {

// Convert the samples in the input AVFrame and write them to the output AVFrame.
func SWResample_convert_frame(ctx *SWRContext, src, dest *AVFrame) error {
// TODO: This is likely a terrible idea but the only thing I can get to work
// at the moment. Later find out why swr_convert_frame isn't working.
// Ref: https://stackoverflow.com/questions/77502983/libswresample-why-does-swr-init-change-in-ch-layout-order-so-it-no-longer-m
if err := SWResample_config_frame(ctx, src, dest); err != nil {
return err
}
if err := AVError(C.swr_convert_frame((*C.struct_SwrContext)(ctx), (*C.struct_AVFrame)(dest), (*C.struct_AVFrame)(src))); err != 0 {
return err
} else {
Expand Down

0 comments on commit 60e56f3

Please sign in to comment.