@@ -23,9 +23,12 @@ type demuxer struct {
23
23
24
24
// decoder context - decodes packets into frames
25
25
type decoder struct {
26
- stream int
27
- codec * ff.AVCodecContext
28
- frame * ff.AVFrame // Destination frame
26
+ stream int
27
+ codec * ff.AVCodecContext
28
+ frame * ff.AVFrame // Destination frame
29
+ reframe * ff.AVFrame // Destination frame after resample or resize
30
+ resampler * ff.SWRContext // Resampler for audio
31
+ rescaler * ff.SWSContext // Rescaler for video
29
32
}
30
33
31
34
var _ Decoder = (* demuxer )(nil )
@@ -53,16 +56,13 @@ func newDemuxer(input *ff.AVFormatContext, mapfn DecoderMapFunc) (*demuxer, erro
53
56
// destination frame. If it's nil then it's mostly a copy.
54
57
var result error
55
58
for _ , stream := range streams {
56
- // Get decoder parameters
59
+ // Get decoder parameters and map to a decoder
57
60
parameters , err := mapfn (newStream (stream ))
58
61
if err != nil {
59
62
result = errors .Join (result , err )
60
63
} else if parameters == nil {
61
64
continue
62
- }
63
-
64
- // Create the decoder with the parameters
65
- if decoder , err := demuxer .newDecoder (stream , parameters ); err != nil {
65
+ } else if decoder , err := demuxer .newDecoder (stream , parameters ); err != nil {
66
66
result = errors .Join (result , err )
67
67
} else {
68
68
streamNum := stream .Index ()
@@ -86,11 +86,29 @@ func newDemuxer(input *ff.AVFormatContext, mapfn DecoderMapFunc) (*demuxer, erro
86
86
return demuxer , nil
87
87
}
88
88
89
- func (d * demuxer ) newDecoder (stream * ff.AVStream , parameters Parameters ) (* decoder , error ) {
89
+ func (d * demuxer ) newDecoder (stream * ff.AVStream , dest Parameters ) (* decoder , error ) {
90
90
decoder := new (decoder )
91
91
decoder .stream = stream .Id ()
92
92
93
- // TODO: Use parameters to create the decoder
93
+ // Use parameters to create the decoder resampler or resizer
94
+ src := stream .CodecPar ()
95
+ if equals , err := equalsStream (dest , src ); err != nil {
96
+ return nil , err
97
+ } else if ! equals {
98
+ switch src .CodecType () {
99
+ case ff .AVMEDIA_TYPE_AUDIO :
100
+ fmt .Println ("TODO: set up resampler" , dest )
101
+ case ff .AVMEDIA_TYPE_VIDEO :
102
+ if rescaler , frame , err := newResizer (dest , src ); err != nil {
103
+ return nil , err
104
+ } else {
105
+ decoder .rescaler = rescaler
106
+ decoder .reframe = frame
107
+ }
108
+ default :
109
+ return nil , fmt .Errorf ("new decoder: unsupported stream type %v" , src .CodecType ())
110
+ }
111
+ }
94
112
95
113
// Create a codec context for the decoder
96
114
codec := ff .AVCodec_find_decoder (stream .CodecPar ().CodecID ())
@@ -123,6 +141,24 @@ func (d *demuxer) newDecoder(stream *ff.AVStream, parameters Parameters) (*decod
123
141
return decoder , nil
124
142
}
125
143
144
+ func newResizer (dest Parameters , src * ff.AVCodecParameters ) (* ff.SWSContext , * ff.AVFrame , error ) {
145
+ // Get native pixel format
146
+ dest_pixel_format := ff .AVUtil_get_pix_fmt (dest .PixelFormat ())
147
+
148
+ // Create scaling context and destination frame
149
+ if ctx := ff .SWScale_get_context (
150
+ src .Width (), src .Height (), src .PixelFormat (), // source
151
+ dest .Width (), dest .Height (), dest_pixel_format , // destination
152
+ ff .SWS_BILINEAR , nil , nil , nil ); ctx == nil {
153
+ return nil , nil , errors .New ("failed to allocate swscale context" )
154
+ } else if frame := ff .AVUtil_frame_alloc (); frame == nil {
155
+ ff .SWScale_free_context (ctx )
156
+ return nil , nil , errors .New ("failed to allocate frame" )
157
+ } else {
158
+ return ctx , frame , nil
159
+ }
160
+ }
161
+
126
162
func (d * demuxer ) close () error {
127
163
var result error
128
164
@@ -149,6 +185,21 @@ func (d *decoder) close() error {
149
185
ff .AVCodec_free_context (d .codec )
150
186
}
151
187
188
+ // Free the resampler
189
+ if d .resampler != nil {
190
+ ff .SWResample_free (d .resampler )
191
+ }
192
+
193
+ // Free the rescaler
194
+ if d .rescaler != nil {
195
+ ff .SWScale_free_context (d .rescaler )
196
+ }
197
+
198
+ // Free rescaler frame
199
+ if d .reframe != nil {
200
+ ff .AVUtil_frame_free (d .reframe )
201
+ }
202
+
152
203
// Free destination frame
153
204
if d .frame != nil {
154
205
ff .AVUtil_frame_free (d .frame )
@@ -235,6 +286,7 @@ func (d *decoder) decode(packet *ff.AVPacket, demuxfn DecoderFunc, framefn Frame
235
286
}
236
287
237
288
// get all the available frames from the decoder
289
+ var result error
238
290
for {
239
291
if err := ff .AVCodec_receive_frame (d .codec , d .frame ); errors .Is (err , syscall .EAGAIN ) || errors .Is (err , io .EOF ) {
240
292
// Finished decoding packet or EOF
@@ -243,39 +295,121 @@ func (d *decoder) decode(packet *ff.AVPacket, demuxfn DecoderFunc, framefn Frame
243
295
return err
244
296
}
245
297
246
- // Pass the frame
247
- if err := framefn (newFrame (d .frame )); errors .Is (err , io .EOF ) {
248
- // End early
298
+ // Resample or resize the frame, then pass to the frame function
299
+ if frame , err := d .re (d .frame ); err != nil {
300
+ return err
301
+ } else if err := framefn (newFrame (frame )); errors .Is (err , io .EOF ) {
302
+ // End early, return EOF
303
+ result = io .EOF
249
304
break
250
305
} else if err != nil {
251
306
return err
252
307
}
253
-
254
- // Resample or resize the frame, then pass back
255
- /*
256
- if frame, err := codec.(*decoder).re(r.frame); err != nil {
257
- return err
258
- } else if err := fn(frame); errors.Is(err, io.EOF) {
259
- // End early
260
- break
261
- } else if err != nil {
262
- return err
263
- }
264
- */
265
308
}
266
309
267
- // TODO: Flush
268
- /*
269
- if frame, err := codec.(*decoder) .re(nil); err != nil {
310
+ // Flush the resizer or resampler if we haven't received an EOF
311
+ if result == nil {
312
+ if frame , err := d .re (nil ); err != nil {
270
313
return err
271
314
} else if frame == nil {
272
315
// NOOP
273
- } else if err := fn( frame); errors.Is(err, io.EOF) {
316
+ } else if err := framefn ( newFrame ( d . frame ) ); errors .Is (err , io .EOF ) {
274
317
// NOOP
275
318
} else if err != nil {
276
319
return err
277
- }*/
320
+ }
321
+ }
278
322
279
- // Return success
323
+ // Return success or EOF
324
+ return result
325
+ }
326
+
327
+ func (d * decoder ) re (src * ff.AVFrame ) (* ff.AVFrame , error ) {
328
+ switch d .codec .Codec ().Type () {
329
+ case ff .AVMEDIA_TYPE_AUDIO :
330
+ fmt .Println ("TODO: resample audio" , src )
331
+ case ff .AVMEDIA_TYPE_VIDEO :
332
+ if d .rescaler != nil && src != nil {
333
+ // Rescale the video
334
+ if err := rescale (d .rescaler , d .reframe , src ); err != nil {
335
+ return nil , err
336
+ } else {
337
+ return d .reframe , nil
338
+ }
339
+ }
340
+ }
341
+
342
+ // if err := decoder.rescale(decoder.frame, src); err != nil {
343
+ // return nil, err
344
+ // }
345
+
346
+ // NO-OP - just return the source frame
347
+ return src , nil
348
+ }
349
+
350
+ func rescale (ctx * ff.SWSContext , dest , src * ff.AVFrame ) error {
351
+ // Copy properties from source
352
+ if err := ff .AVUtil_frame_copy_props (dest , src ); err != nil {
353
+ return fmt .Errorf ("failed to copy props: %w" , err )
354
+ }
355
+ // Perform rescale
356
+ if err := ff .SWScale_scale_frame (ctx , dest , src , false ); err != nil {
357
+ return fmt .Errorf ("SWScale_scale_frame: %w" , err )
358
+ }
280
359
return nil
281
360
}
361
+
362
+ // Return an error if the parameters don't match the stream type (AUDIO, VIDEO)
363
+ // Return true if the codec parameters are compatible with the stream
364
+ func equalsStream (dest Parameters , src * ff.AVCodecParameters ) (bool , error ) {
365
+ switch src .CodecType () {
366
+ case ff .AVMEDIA_TYPE_AUDIO :
367
+ if ! dest .Type ().Is (AUDIO ) {
368
+ return false , fmt .Errorf ("source is audio, but destination is %v" , dest .Type ())
369
+ } else {
370
+ return equalsAudioPar (dest , src ), nil
371
+ }
372
+ case ff .AVMEDIA_TYPE_VIDEO :
373
+ if ! dest .Type ().Is (VIDEO ) {
374
+ return false , fmt .Errorf ("source is video, but destination are %v" , dest .Type ())
375
+ } else {
376
+ return equalsVideoPar (dest , src ), nil
377
+ }
378
+ default :
379
+ return false , fmt .Errorf ("unsupported source %v" , src .CodecType ())
380
+ }
381
+ }
382
+
383
+ // Return true if the audio parameters are compatible with the stream
384
+ func equalsAudioPar (parameters Parameters , codec * ff.AVCodecParameters ) bool {
385
+ samplefmt := ff .AVUtil_get_sample_fmt_name (codec .SampleFormat ())
386
+ if samplefmt != parameters .SampleFormat () {
387
+ return false
388
+ }
389
+ ch_layout := ff .AVChannelLayout (codec .ChannelLayout ())
390
+ channellayout , err := ff .AVUtil_channel_layout_describe (& ch_layout )
391
+ if err != nil || channellayout != parameters .ChannelLayout () {
392
+ return false
393
+ }
394
+ if codec .Samplerate () != parameters .Samplerate () {
395
+ return false
396
+ }
397
+ // Matches
398
+ return true
399
+ }
400
+
401
+ // Return true if the video parameters are compatible with the stream
402
+ func equalsVideoPar (parameters Parameters , codec * ff.AVCodecParameters ) bool {
403
+ pixelfmt := ff .AVUtil_get_pix_fmt_name (codec .PixelFormat ())
404
+ if pixelfmt != parameters .PixelFormat () {
405
+ return false
406
+ }
407
+ if codec .Width () != parameters .Width () {
408
+ return false
409
+ }
410
+ if codec .Height () != parameters .Height () {
411
+ return false
412
+ }
413
+ // Matches
414
+ return true
415
+ }
0 commit comments