Skip to content

Commit 609b7f7

Browse files
committed
All changes
1 parent 73aabe7 commit 609b7f7

File tree

17 files changed

+592
-260
lines changed

17 files changed

+592
-260
lines changed

cmd/cli/decode.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func (cmd *DecodeCmd) Run(globals *Globals) error {
3939
defer reader.Close()
4040

4141
// Create a decoder - copy streams
42-
decoder, err := reader.Decoder(nil)
42+
decoder, err := reader.Decoder(nil, false)
4343
if err != nil {
4444
return err
4545
}

decoder.go

Lines changed: 112 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ type demuxer struct {
2525
type decoder struct {
2626
stream int
2727
codec *ff.AVCodecContext
28+
dest *par // Destination parameters
29+
timeBase ff.AVRational // Timebase for the stream
2830
frame *ff.AVFrame // Destination frame
2931
reframe *ff.AVFrame // Destination frame after resample or resize
3032
resampler *ff.SWRContext // Resampler for audio
@@ -36,7 +38,7 @@ var _ Decoder = (*demuxer)(nil)
3638
////////////////////////////////////////////////////////////////////////////
3739
// LIFECYCLE
3840

39-
func newDemuxer(input *ff.AVFormatContext, mapfn DecoderMapFunc) (*demuxer, error) {
41+
func newDemuxer(input *ff.AVFormatContext, mapfn DecoderMapFunc, force bool) (*demuxer, error) {
4042
demuxer := new(demuxer)
4143
demuxer.input = input
4244
demuxer.decoders = make(map[int]*decoder)
@@ -62,7 +64,7 @@ func newDemuxer(input *ff.AVFormatContext, mapfn DecoderMapFunc) (*demuxer, erro
6264
result = errors.Join(result, err)
6365
} else if parameters == nil {
6466
continue
65-
} else if decoder, err := demuxer.newDecoder(stream, parameters); err != nil {
67+
} else if decoder, err := demuxer.newDecoder(stream, parameters.(*par), force); err != nil {
6668
result = errors.Join(result, err)
6769
} else {
6870
streamNum := stream.Index()
@@ -86,15 +88,21 @@ func newDemuxer(input *ff.AVFormatContext, mapfn DecoderMapFunc) (*demuxer, erro
8688
return demuxer, nil
8789
}
8890

89-
func (d *demuxer) newDecoder(stream *ff.AVStream, dest Parameters) (*decoder, error) {
91+
func (d *demuxer) newDecoder(stream *ff.AVStream, dest *par, force bool) (*decoder, error) {
9092
decoder := new(decoder)
9193
decoder.stream = stream.Id()
94+
decoder.dest = dest
95+
decoder.timeBase = stream.TimeBase()
9296

9397
// Use parameters to create the decoder resampler or resizer
9498
src := stream.CodecPar()
95-
if equals, err := equalsStream(dest, src); err != nil {
99+
equals, err := equalsStream(dest, src)
100+
if err != nil {
96101
return nil, err
97-
} else if !equals {
102+
}
103+
104+
// We resample or rescale if the parameters don't match, or if we're forced
105+
if !equals || force {
98106
switch src.CodecType() {
99107
case ff.AVMEDIA_TYPE_AUDIO:
100108
if resampler, frame, err := newResampler(dest, src); err != nil {
@@ -135,7 +143,7 @@ func (d *demuxer) newDecoder(stream *ff.AVStream, dest Parameters) (*decoder, er
135143
return nil, errors.Join(decoder.close(), err)
136144
}
137145

138-
// Create a frame for decoder output - after resize/resample
146+
// Create a frame for decoder output - before resize/resample
139147
if frame := ff.AVUtil_frame_alloc(); frame == nil {
140148
return nil, errors.Join(decoder.close(), errors.New("failed to allocate frame"))
141149
} else {
@@ -146,38 +154,28 @@ func (d *demuxer) newDecoder(stream *ff.AVStream, dest Parameters) (*decoder, er
146154
return decoder, nil
147155
}
148156

149-
func newResizer(dest Parameters, src *ff.AVCodecParameters) (*ff.SWSContext, *ff.AVFrame, error) {
150-
// Get native pixel format
151-
dest_pixel_format := ff.AVUtil_get_pix_fmt(dest.PixelFormat())
152-
157+
func newResizer(dest *par, src *ff.AVCodecParameters) (*ff.SWSContext, *ff.AVFrame, error) {
153158
// Create scaling context and destination frame
154-
if ctx := ff.SWScale_get_context(
159+
ctx := ff.SWScale_get_context(
155160
src.Width(), src.Height(), src.PixelFormat(), // source
156-
dest.Width(), dest.Height(), dest_pixel_format, // destination
157-
ff.SWS_BILINEAR, nil, nil, nil); ctx == nil {
161+
dest.videopar.Width, dest.videopar.Height, dest.videopar.PixelFormat, // destination
162+
ff.SWS_BILINEAR, nil, nil, nil)
163+
if ctx == nil {
158164
return nil, nil, errors.New("failed to allocate swscale context")
159-
} else if frame := ff.AVUtil_frame_alloc(); frame == nil {
165+
}
166+
167+
// Create a new frame for the resizing video
168+
frame := ff.AVUtil_frame_alloc()
169+
if frame == nil {
160170
ff.SWScale_free_context(ctx)
161171
return nil, nil, errors.New("failed to allocate frame")
162-
} else {
163-
// Set frame parameters
164-
frame.SetPixFmt(dest_pixel_format)
165-
frame.SetWidth(dest.Width())
166-
frame.SetHeight(dest.Height())
167-
168-
// Return success
169-
return ctx, frame, nil
170172
}
171-
}
172173

173-
func newResampler(dest Parameters, src *ff.AVCodecParameters) (*ff.SWRContext, *ff.AVFrame, error) {
174-
// Get native sample format and channel layout
175-
var dest_channel_layout ff.AVChannelLayout
176-
dest_sample_format := ff.AVUtil_get_sample_fmt(dest.SampleFormat())
177-
if err := ff.AVUtil_channel_layout_from_string(&dest_channel_layout, dest.ChannelLayout()); err != nil {
178-
return nil, nil, fmt.Errorf("failed to get channel layout: %w", err)
179-
}
174+
// Return success
175+
return ctx, frame, nil
176+
}
180177

178+
func newResampler(dest *par, src *ff.AVCodecParameters) (*ff.SWRContext, *ff.AVFrame, error) {
181179
// Create a new resampler
182180
ctx := ff.SWResample_alloc()
183181
if ctx == nil {
@@ -186,7 +184,7 @@ func newResampler(dest Parameters, src *ff.AVCodecParameters) (*ff.SWRContext, *
186184

187185
// Set options to covert from the codec frame to the decoder frame
188186
if err := ff.SWResample_set_opts(ctx,
189-
dest_channel_layout, dest_sample_format, dest.Samplerate(), // destination
187+
dest.audiopar.Ch, dest.audiopar.SampleFormat, dest.audiopar.Samplerate, // destination
190188
src.ChannelLayout(), src.SampleFormat(), src.Samplerate(), // source
191189
); err != nil {
192190
ff.SWResample_free(ctx)
@@ -206,19 +204,14 @@ func newResampler(dest Parameters, src *ff.AVCodecParameters) (*ff.SWRContext, *
206204
return nil, nil, errors.New("failed to allocate frame")
207205
}
208206

209-
// Set frame parameters
210-
frame.SetSampleRate(dest.Samplerate())
211-
frame.SetSampleFormat(dest_sample_format)
212-
frame.SetChannelLayout(dest_channel_layout)
213-
214207
// Return success
215208
return ctx, frame, nil
216209
}
217210

218211
func (d *demuxer) close() error {
219212
var result error
220213

221-
// Free decoded frame
214+
// Free source frame
222215
if d.frame != nil {
223216
ff.AVUtil_frame_free(d.frame)
224217
}
@@ -251,16 +244,16 @@ func (d *decoder) close() error {
251244
ff.SWScale_free_context(d.rescaler)
252245
}
253246

254-
// Free rescaler frame
255-
if d.reframe != nil {
256-
ff.AVUtil_frame_free(d.reframe)
257-
}
258-
259247
// Free destination frame
260248
if d.frame != nil {
261249
ff.AVUtil_frame_free(d.frame)
262250
}
263251

252+
// Free rescaled/resized frame
253+
if d.reframe != nil {
254+
ff.AVUtil_frame_free(d.reframe)
255+
}
256+
264257
// Return any errors
265258
return result
266259
}
@@ -313,9 +306,10 @@ FOR_LOOP:
313306
return err
314307
}
315308
}
316-
// Unreference the packet
317-
ff.AVCodec_packet_unref(packet)
318309
}
310+
311+
// Unreference the packet
312+
ff.AVCodec_packet_unref(packet)
319313
}
320314

321315
// Flush the decoders
@@ -332,7 +326,7 @@ FOR_LOOP:
332326

333327
func (d *decoder) decode(packet *ff.AVPacket, demuxfn DecoderFunc, framefn FrameFunc) error {
334328
if demuxfn != nil {
335-
// Send the packet to the user defined packet function
329+
// Send the packet (or a nil to flush) to the user defined packet function
336330
return demuxfn(newPacket(packet))
337331
}
338332

@@ -352,27 +346,49 @@ func (d *decoder) decode(packet *ff.AVPacket, demuxfn DecoderFunc, framefn Frame
352346
}
353347

354348
// Resample or resize the frame, then pass to the frame function
355-
if frame, err := d.re(d.frame); err != nil {
349+
frame, err := d.re(d.frame)
350+
if err != nil {
356351
return err
357-
} else if err := framefn(newFrame(frame)); errors.Is(err, io.EOF) {
352+
}
353+
354+
// Copy over the timebase and ptr
355+
frame.SetTimeBase(d.timeBase)
356+
frame.SetPts(d.frame.Pts())
357+
358+
// Pass back to the caller
359+
if err := framefn(newFrame(frame)); errors.Is(err, io.EOF) {
358360
// End early, return EOF
359361
result = io.EOF
360362
break
361363
} else if err != nil {
362364
return err
363365
}
366+
367+
// Re-allocate frames for next iteration
368+
ff.AVUtil_frame_unref(d.frame)
369+
ff.AVUtil_frame_unref(d.reframe)
364370
}
365371

366372
// Flush the resizer or resampler if we haven't received an EOF
367373
if result == nil {
368-
if frame, err := d.re(nil); err != nil {
369-
return err
370-
} else if frame == nil {
371-
// NOOP
372-
} else if err := framefn(newFrame(d.frame)); errors.Is(err, io.EOF) {
373-
// NOOP
374-
} else if err != nil {
375-
return err
374+
finished := false
375+
for {
376+
if finished {
377+
break
378+
}
379+
if frame, err := d.reflush(d.frame); err != nil {
380+
return err
381+
} else if frame == nil {
382+
finished = true
383+
} else if err := framefn(newFrame(frame)); errors.Is(err, io.EOF) {
384+
finished = true
385+
} else if err != nil {
386+
return err
387+
}
388+
389+
// Re-allocate frames for next iteration
390+
ff.AVUtil_frame_unref(d.frame)
391+
ff.AVUtil_frame_unref(d.reframe)
376392
}
377393
}
378394

@@ -384,8 +400,8 @@ func (d *decoder) re(src *ff.AVFrame) (*ff.AVFrame, error) {
384400
switch d.codec.Codec().Type() {
385401
case ff.AVMEDIA_TYPE_AUDIO:
386402
if d.resampler != nil && src != nil {
387-
// Resample the audio
388-
if err := resample(d.resampler, d.reframe, src); err != nil {
403+
// Resample the audio or flush if src is nil
404+
if err := d.resample(d.reframe, src); err != nil {
389405
return nil, err
390406
} else {
391407
return d.reframe, nil
@@ -394,7 +410,7 @@ func (d *decoder) re(src *ff.AVFrame) (*ff.AVFrame, error) {
394410
case ff.AVMEDIA_TYPE_VIDEO:
395411
if d.rescaler != nil && src != nil {
396412
// Rescale the video
397-
if err := rescale(d.rescaler, d.reframe, src); err != nil {
413+
if err := d.rescale(d.reframe, src); err != nil {
398414
return nil, err
399415
} else {
400416
return d.reframe, nil
@@ -406,36 +422,58 @@ func (d *decoder) re(src *ff.AVFrame) (*ff.AVFrame, error) {
406422
return src, nil
407423
}
408424

409-
func rescale(ctx *ff.SWSContext, dest, src *ff.AVFrame) error {
410-
// Copy properties from source
411-
if err := ff.AVUtil_frame_copy_props(dest, src); err != nil {
412-
return fmt.Errorf("failed to copy props: %w", err)
425+
func (d *decoder) reflush(src *ff.AVFrame) (*ff.AVFrame, error) {
426+
switch d.codec.Codec().Type() {
427+
case ff.AVMEDIA_TYPE_AUDIO:
428+
if d.resampler != nil {
429+
if num_samples := ff.SWResample_get_delay(d.resampler, int64(src.SampleRate())); num_samples > 0 {
430+
fmt.Println("TODO there are", num_samples, "samples left")
431+
}
432+
}
433+
}
434+
435+
// No flush necessary
436+
return nil, nil
437+
}
438+
439+
func (d *decoder) rescale(dest, src *ff.AVFrame) error {
440+
dest.SetPixFmt(d.dest.videopar.PixelFormat)
441+
dest.SetWidth(d.dest.videopar.Width)
442+
dest.SetHeight(d.dest.videopar.Height)
443+
444+
// Allocate rescaled frame
445+
if err := ff.AVUtil_frame_get_buffer(dest, false); err != nil {
446+
return fmt.Errorf("AVUtil_frame_get_buffer: %w", err)
413447
}
448+
414449
// Perform rescale
415-
if err := ff.SWScale_scale_frame(ctx, dest, src, false); err != nil {
450+
if err := ff.SWScale_scale_frame(d.rescaler, dest, src, false); err != nil {
416451
return fmt.Errorf("SWScale_scale_frame: %w", err)
417452
}
418453
return nil
419454
}
420455

421-
func resample(ctx *ff.SWRContext, dest, src *ff.AVFrame) error {
422-
// Copy properties from source
423-
//if err := ff.AVUtil_frame_copy_props(dest, src); err != nil {
424-
// return fmt.Errorf("failed to copy props: %w", err)
425-
//}
456+
func (d *decoder) resample(dest, src *ff.AVFrame) error {
457+
dest.SetChannelLayout(d.dest.audiopar.Ch)
458+
dest.SetSampleFormat(d.dest.audiopar.SampleFormat)
459+
dest.SetSampleRate(d.dest.audiopar.Samplerate)
426460

427-
dest_samples, err := ff.SWResample_get_out_samples(ctx, src.NumSamples())
428-
if err != nil {
461+
if dest_samples, err := ff.SWResample_get_out_samples(d.resampler, src.NumSamples()); err != nil {
429462
return fmt.Errorf("SWResample_get_out_samples: %w", err)
463+
} else {
464+
dest.SetNumSamples(dest_samples)
465+
466+
}
467+
468+
// Allocate resampled frame
469+
if err := ff.AVUtil_frame_get_buffer(dest, false); err != nil {
470+
return fmt.Errorf("AVUtil_frame_get_buffer: %w", err)
430471
}
431-
dest.SetNumSamples(dest_samples)
432-
fmt.Println("dest frame=", dest)
433472

434473
// Perform resampling
435-
if err := ff.SWResample_convert_frame(ctx, src, dest); err != nil {
474+
if err := ff.SWResample_convert_frame(d.resampler, src, dest); err != nil {
436475
return fmt.Errorf("SWResample_convert_frame: %w", err)
437476
}
438-
439477
return nil
440478
}
441479

0 commit comments

Comments
 (0)