Skip to content

Commit b9b7452

Browse files
committed
Updated code
1 parent 97d51a9 commit b9b7452

File tree

2 files changed

+61
-21
lines changed

2 files changed

+61
-21
lines changed

pkg/ffmpeg/decoder.go

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type Decoder struct {
1717
stream int
1818
codec *ff.AVCodecContext
1919
dest *Par // Destination parameters
20+
re *Re // Resample/resize
2021
timeBase ff.AVRational // Timebase for the stream
2122
frame *ff.AVFrame // Destination frame
2223
}
@@ -25,21 +26,38 @@ type Decoder struct {
2526
// LIFECYCLE
2627

2728
// Create a stream decoder which can decode packets from the input stream
28-
// TODO: resample and resize frames to the destination parameters
2929
func NewDecoder(stream *ff.AVStream, dest *Par, force bool) (*Decoder, error) {
3030
decoder := new(Decoder)
3131
decoder.stream = stream.Id()
3232
decoder.dest = dest
3333
decoder.timeBase = stream.TimeBase()
3434

35+
// Create a frame for decoder output - before resize/resample
36+
frame := ff.AVUtil_frame_alloc()
37+
if frame == nil {
38+
return nil, errors.New("failed to allocate frame")
39+
}
40+
3541
// Create a codec context for the decoder
3642
codec := ff.AVCodec_find_decoder(stream.CodecPar().CodecID())
3743
if codec == nil {
44+
ff.AVUtil_frame_free(frame)
3845
return nil, fmt.Errorf("failed to find decoder for codec %q", stream.CodecPar().CodecID())
3946
} else if ctx := ff.AVCodec_alloc_context(codec); ctx == nil {
47+
ff.AVUtil_frame_free(frame)
4048
return nil, fmt.Errorf("failed to allocate codec context for codec %q", codec.Name())
4149
} else {
4250
decoder.codec = ctx
51+
decoder.frame = frame
52+
}
53+
54+
// If the destination codec parameters are not nil, then create a resample/resizer
55+
if dest != nil {
56+
if re, err := NewRe(dest, force); err != nil {
57+
return nil, errors.Join(err, decoder.Close())
58+
} else {
59+
decoder.re = re
60+
}
4361
}
4462

4563
// Copy codec parameters from input stream to output codec context
@@ -52,13 +70,6 @@ func NewDecoder(stream *ff.AVStream, dest *Par, force bool) (*Decoder, error) {
5270
return nil, errors.Join(decoder.Close(), err)
5371
}
5472

55-
// Create a frame for decoder output - before resize/resample
56-
if frame := ff.AVUtil_frame_alloc(); frame == nil {
57-
return nil, errors.Join(decoder.Close(), errors.New("failed to allocate frame"))
58-
} else {
59-
decoder.frame = frame
60-
}
61-
6273
// Return success
6374
return decoder, nil
6475
}
@@ -67,6 +78,11 @@ func NewDecoder(stream *ff.AVStream, dest *Par, force bool) (*Decoder, error) {
6778
func (d *Decoder) Close() error {
6879
var result error
6980

81+
// Free resampler/resizer
82+
if d.re != nil {
83+
result = errors.Join(result, d.re.Close())
84+
}
85+
7086
// Free the codec context
7187
if d.codec != nil {
7288
ff.AVCodec_free_context(d.codec)
@@ -77,30 +93,38 @@ func (d *Decoder) Close() error {
7793
ff.AVUtil_frame_free(d.frame)
7894
}
7995

96+
// Reset fields
97+
d.re = nil
98+
d.codec = nil
99+
d.frame = nil
100+
80101
// Return any errors
81102
return result
82103
}
83104

84105
////////////////////////////////////////////////////////////////////////////////
85106
// PUBLIC METHODS
86107

108+
// Decode a packet into a set of frames to pass back to the
109+
// DecoderFrameFn. If the packet is nil, then the decoder will
110+
// flush any remaining frames.
111+
// TODO: Optionally use the user defined packet function
112+
// if they want to use AVParser
113+
// TODO: The frame sent to DecoderFrameFn needs to have the
114+
// correct timebase, etc set
87115
func (d *Decoder) decode(packet *ff.AVPacket, fn DecoderFrameFn) error {
88116
if fn == nil {
89117
return errors.New("DecoderFrameFn is nil")
90118
}
91119

92-
//if demuxfn != nil {
93-
// Send the packet (or a nil to flush) to the user defined packet function
94-
// return demuxfn(newPacket(packet, d.stream, d.codec.Codec().Type(), d.timeBase))
95-
//}
96-
97120
// Submit the packet to the decoder (nil packet will flush the decoder)
98121
if err := ff.AVCodec_send_packet(d.codec, packet); err != nil {
99122
return err
100123
}
101124

102125
// get all the available frames from the decoder
103126
var result error
127+
var dest *Frame
104128
for {
105129
// End early if we've received an EOF
106130
if result != nil {
@@ -115,25 +139,38 @@ func (d *Decoder) decode(packet *ff.AVPacket, fn DecoderFrameFn) error {
115139
return err
116140
}
117141

142+
// Obtain the output frame. If a new frame is returned, it is
143+
// managed by the rescaler/resizer and no need to unreference it
144+
// later.
145+
if d.re != nil {
146+
if frame, err := d.re.Frame((*Frame)(d.frame)); err != nil {
147+
result = errors.Join(result, err)
148+
} else {
149+
dest = frame
150+
}
151+
} else {
152+
dest = (*Frame)(d.frame)
153+
}
154+
118155
// TODO: Modify Pts?
156+
// What else do we need to copy across?
157+
fmt.Println("TODO", d.timeBase, dest.TimeBase(), ff.AVTimestamp(dest.Pts()))
158+
if dest.Pts() == PTS_UNDEFINED {
159+
(*ff.AVFrame)(dest).SetPts(d.frame.Pts())
160+
}
119161

120162
// Pass back to the caller
121-
if err := fn(d.stream, (*Frame)(d.frame)); errors.Is(err, io.EOF) {
163+
if err := fn(d.stream, dest); errors.Is(err, io.EOF) {
122164
// End early, return EOF
123165
result = io.EOF
124166
} else if err != nil {
125167
return err
126168
}
127169

128-
// Re-allocate frames for next iteration
170+
// Re-allocate frame for next iteration
129171
ff.AVUtil_frame_unref(d.frame)
130172
}
131173

132-
// Flush
133-
if err := fn(d.stream, nil); err != nil && !errors.Is(err, io.EOF) {
134-
result = errors.Join(result, err)
135-
}
136-
137174
// Return success or EOF
138175
return result
139176
}

pkg/ffmpeg/reader_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ func Test_reader_003(t *testing.T) {
6363
defer media.Close()
6464

6565
framefn := func(stream int, frame *ffmpeg.Frame) error {
66-
t.Logf("Frame %v[%d] => %v", frame.Type(), stream, time.Duration(frame.Ts()*float64(time.Second)).Truncate(time.Millisecond))
66+
// Receive a nil frame at the end of each packet
67+
if frame != nil {
68+
t.Logf("Frame %v[%d] => %v", frame.Type(), stream, time.Duration(frame.Ts()*float64(time.Second)).Truncate(time.Millisecond))
69+
}
6770
return nil
6871
}
6972

0 commit comments

Comments
 (0)