@@ -4,9 +4,11 @@ import (
4
4
"context"
5
5
"encoding/json"
6
6
"errors"
7
+ "fmt"
7
8
"io"
8
9
"slices"
9
10
"strings"
11
+ "sync"
10
12
"time"
11
13
12
14
// Packages
@@ -230,11 +232,102 @@ func (r *Reader) Metadata(keys ...string) []*Metadata {
230
232
// returning an error or io.EOF. The latter will end the decoding process early but
231
233
// will not return an error.
232
234
func (r * Reader ) Decode (ctx context.Context , mapfn DecoderMapFunc , decodefn DecoderFrameFn ) error {
233
- decoders := make (map [int ]* Decoder , r .input .NumStreams ())
235
+ // Map streams to decoders
236
+ decoders , err := r .mapStreams (mapfn )
237
+ if err != nil {
238
+ return err
239
+ }
240
+ defer decoders .Close ()
241
+
242
+ // Do the decoding
243
+ return r .decode (ctx , decoders , decodefn )
244
+ }
245
+
246
+ // Transcode the media stream to a writer
247
+ // As per the decode method, the map function is called for each stream and should return the
248
+ // parameters for the destination. If the map function returns nil for a stream, then
249
+ // the stream is ignored.
250
+ func (r * Reader ) Transcode (ctx context.Context , w io.Writer , mapfn DecoderMapFunc , opt ... Opt ) error {
251
+ // Map streams to decoders
252
+ decoders , err := r .mapStreams (mapfn )
253
+ if err != nil {
254
+ return err
255
+ }
256
+ defer decoders .Close ()
257
+
258
+ // Add streams to the output
259
+ for _ , decoder := range decoders {
260
+ opt = append (opt , OptStream (decoder .stream , decoder .par ))
261
+ }
262
+
263
+ // Create an output
264
+ output , err := NewWriter (w , opt ... )
265
+ if err != nil {
266
+ return err
267
+ }
268
+ defer output .Close ()
269
+
270
+ // One go-routine for decoding, one for encoding
271
+ var wg sync.WaitGroup
272
+ var result error
273
+
274
+ // Make a channel for transcoding frames. The decoder should
275
+ // be ahead of the encoder, so there is probably no need to
276
+ // create a buffered channel.
277
+ ch := make (chan * Frame )
278
+
279
+ // Decoding
280
+ wg .Add (1 )
281
+ go func () {
282
+ defer wg .Done ()
283
+ if err := r .decode (ctx , decoders , func (stream int , frame * Frame ) error {
284
+ ch <- frame
285
+ return nil
286
+ }); err != nil {
287
+ result = err
288
+ }
289
+ // Close channel at the end of decoding
290
+ close (ch )
291
+ }()
292
+
293
+ // Encoding
294
+ wg .Add (1 )
295
+ go func () {
296
+ defer wg .Done ()
297
+ for frame := range ch {
298
+ fmt .Println ("TODO: Write frame to output" , frame )
299
+ }
300
+ }()
301
+
302
+ // Wait for the process to finish
303
+ wg .Wait ()
304
+
305
+ // Return any errors
306
+ return result
307
+ }
308
+
309
+ ////////////////////////////////////////////////////////////////////////////////
310
+ // PRIVATE METHODS - DECODE
311
+
312
+ type decoderMap map [int ]* Decoder
313
+
314
+ func (d decoderMap ) Close () error {
315
+ var result error
316
+ for _ , decoder := range d {
317
+ if err := decoder .Close (); err != nil {
318
+ result = errors .Join (result , err )
319
+ }
320
+ }
321
+ return result
322
+ }
323
+
324
+ // Map streams to decoders, and return the decoders
325
+ func (r * Reader ) mapStreams (fn DecoderMapFunc ) (decoderMap , error ) {
326
+ decoders := make (decoderMap , r .input .NumStreams ())
234
327
235
328
// Standard decoder map function copies all streams
236
- if mapfn == nil {
237
- mapfn = func (_ int , par * Par ) (* Par , error ) {
329
+ if fn == nil {
330
+ fn = func (_ int , par * Par ) (* Par , error ) {
238
331
return par , nil
239
332
}
240
333
}
@@ -247,7 +340,7 @@ func (r *Reader) Decode(ctx context.Context, mapfn DecoderMapFunc, decodefn Deco
247
340
stream_index := stream .Index ()
248
341
249
342
// Get decoder parameters and map to a decoder
250
- par , err := mapfn (stream .Id (), & Par {
343
+ par , err := fn (stream .Id (), & Par {
251
344
AVCodecParameters : * stream .CodecPar (),
252
345
})
253
346
if err != nil {
@@ -268,25 +361,15 @@ func (r *Reader) Decode(ctx context.Context, mapfn DecoderMapFunc, decodefn Deco
268
361
result = errors .Join (result , ErrBadParameter .With ("no streams to decode" ))
269
362
}
270
363
271
- // Now we have a map of decoders, we can start decoding
272
- if result == nil {
273
- result = r .decode (ctx , decoders , decodefn )
274
- }
275
-
276
- // Release resources
277
- for _ , decoder := range decoders {
278
- if err := decoder .Close (); err != nil {
279
- result = errors .Join (result , err )
280
- }
364
+ // If there are errors, then free the decoders
365
+ if result != nil {
366
+ result = errors .Join (result , decoders .Close ())
281
367
}
282
368
283
369
// Return any errors
284
- return result
370
+ return decoders , result
285
371
}
286
372
287
- ////////////////////////////////////////////////////////////////////////////////
288
- // PRIVATE METHODS - DECODE
289
-
290
373
func (r * Reader ) decode (ctx context.Context , decoders map [int ]* Decoder , fn DecoderFrameFn ) error {
291
374
// Allocate a packet
292
375
packet := ff .AVCodec_packet_alloc ()
0 commit comments