Repository navigation
Expand file tree
/
Copy pathformat_context.go
More file actions
561 lines (483 loc) · 17.1 KB
/
Copy pathformat_context.go
File metadata and controls
561 lines (483 loc) · 17.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
package astiav
//#include <libavcodec/avcodec.h>
//#include <libavformat/avformat.h>
//#include "format_context.h"
import "C"
import (
"errors"
"fmt"
"math"
"sync"
"unsafe"
)
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html
type FormatContext struct {
c *C.AVFormatContext
}
func newFormatContextFromC(c *C.AVFormatContext) *FormatContext {
if c == nil {
return nil
}
fc := &FormatContext{c: c}
classers.set(fc)
return fc
}
var _ Classer = (*FormatContext)(nil)
// https://ffmpeg.org/doxygen/9.0/group__lavf__core.html#gac7a91abf2f59648d995894711f070f62
func AllocFormatContext() *FormatContext {
return newFormatContextFromC(C.avformat_alloc_context())
}
// https://ffmpeg.org/doxygen/9.0/avformat_8h.html#af5930942120e38a4766dc0bb9e4cae74
func AllocOutputFormatContext(of *OutputFormat, formatName, filename string) (*FormatContext, error) {
fonc := (*C.char)(nil)
if len(formatName) > 0 {
fonc = C.CString(formatName)
defer C.free(unsafe.Pointer(fonc))
}
finc := (*C.char)(nil)
if len(filename) > 0 {
finc = C.CString(filename)
defer C.free(unsafe.Pointer(finc))
}
var ofc *C.AVOutputFormat
if of != nil {
ofc = of.c
}
var fcc *C.AVFormatContext
if err := newError(C.avformat_alloc_output_context2(&fcc, ofc, fonc, finc)); err != nil {
return nil, err
}
return newFormatContextFromC(fcc), nil
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__core.html#gac2990b13b68e831a408fce8e1d0d6445
func (fc *FormatContext) Free() {
if fc.c != nil {
formatContextIOOpeners.del(fc)
// Make sure to clone the classer before freeing the object since
// the C free method may reset the pointer
c := newClonedClasser(fc)
C.avformat_free_context(fc.c)
fc.c = nil
// Make sure to remove from classers after freeing the object since
// the C free method may use methods needing the classer
if c != nil {
classers.del(c)
}
}
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a972a02b9e3b542a426e323a8f8e3ea41
func (fc *FormatContext) BitRate() int64 {
return int64(fc.c.bit_rate)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a0c396740b9a2487aa57d4352d2dc1687
func (fc *FormatContext) Class() *Class {
if fc.c == nil {
return nil
}
return newClassFromC(unsafe.Pointer(fc.c))
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a4e6076343df1ffc2e16cedbba3f3f397
func (fc *FormatContext) CtxFlags() FormatContextCtxFlags {
return FormatContextCtxFlags(fc.c.ctx_flags)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#ad0ea78ac48f5bb0a15a15c1c472744d9
func (fc *FormatContext) Duration() int64 {
return int64(fc.c.duration)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a0302506d4b3434da77b8b3db43821aa0
func (fc *FormatContext) EventFlags() FormatEventFlags {
return FormatEventFlags(fc.c.event_flags)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a32379cc371463b235d54235d4af06a15
func (fc *FormatContext) Flags() FormatContextFlags {
return FormatContextFlags(fc.c.flags)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a32379cc371463b235d54235d4af06a15
func (fc *FormatContext) SetFlags(f FormatContextFlags) {
fc.c.flags = C.int(f)
}
type FormatContextIOCloseFunc func(s *IOContext) error
type FormatContextIOOpenFunc func(filename string, flags IOContextFlags, d *Dictionary) (*IOContext, error)
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#af3f615ad9ff79fb90f4eb136a1f58065
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a17bbcfc18f75f119dd6c0a15a1c7d935
func (fc *FormatContext) SetIOOpener(openFunc FormatContextIOOpenFunc, closeFunc FormatContextIOCloseFunc) {
if openFunc != nil {
formatContextIOOpeners.setIOOpener(fc, openFunc, closeFunc)
fc.c.io_open = (*[0]byte)(C.astiavFormatContextIOOpen)
if closeFunc != nil {
fc.c.io_close2 = (*[0]byte)(C.astiavFormatContextIOClose)
} else {
fc.c.io_close2 = nil
}
} else {
formatContextIOOpeners.del(fc)
fc.c.io_open = nil
fc.c.io_close2 = nil
}
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a5b37acfe4024d92ee510064e80920b40
func (fc *FormatContext) SetIOInterrupter(i *IOInterrupter) {
if i == nil {
fc.c.interrupt_callback = C.AVIOInterruptCB{}
} else {
fc.c.interrupt_callback = *i.c
}
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a6c01f25ef062e0398b0b55dd337246ed
func (fc *FormatContext) InputFormat() *InputFormat {
return newInputFormatFromC(fc.c.iformat)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a5e6814c9de3c272396f07e2ff18c7b27
func (fc *FormatContext) IOFlags() IOContextFlags {
return IOContextFlags(fc.c.avio_flags)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a4d860662c014f88277c8f20e238fa694
func (fc *FormatContext) MaxAnalyzeDuration() int64 {
return int64(fc.c.max_analyze_duration)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a3019a56080ed2e3297ff25bc2ff88adf
func (fc *FormatContext) Metadata() *Dictionary {
return newDictionaryFromC(fc.c.metadata)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a3019a56080ed2e3297ff25bc2ff88adf
func (fc *FormatContext) SetMetadata(d *Dictionary) {
if d == nil {
fc.c.metadata = nil
} else {
fc.c.metadata = d.c
}
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a6f60043baf4abd0d201ccefc27bb4306
func (fc *FormatContext) NbChapters() int {
return int(fc.c.nb_chapters)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#ac17d5fc2dcdb00806cc83b02d9f940f3
func (fc *FormatContext) Chapters() (cs []*Chapter) {
ccs := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.AVChapter)(nil))](*C.AVChapter))(unsafe.Pointer(fc.c.chapters))
for i := 0; i < fc.NbChapters(); i++ {
cs = append(cs, newChapterFromC(ccs[i]))
}
return
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a58c8c4d0ea974e0fcb0ce06fb1174f9f
func (fc *FormatContext) NbPrograms() int {
return int(fc.c.nb_programs)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a4c2c5a4c758966349ff513e95154d062
func (fc *FormatContext) Programs() (ps []*Program) {
pcs := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.AVProgram)(nil))](*C.AVProgram))(unsafe.Pointer(fc.c.programs))
for i := 0; i < fc.NbPrograms(); i++ {
ps = append(ps, newProgramFromC(pcs[i], fc))
}
return
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a0b748d924898b08b89ff4974afd17285
func (fc *FormatContext) NbStreams() int {
return int(fc.c.nb_streams)
}
func (fc *FormatContext) Streams() (ss []*Stream) {
scs := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.AVStream)(nil))](*C.AVStream))(unsafe.Pointer(fc.c.streams))
for i := 0; i < fc.NbStreams(); i++ {
ss = append(ss, newStreamFromC(scs[i]))
}
return
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a37ba86cd5630097cdae01afbc2b40743
func (fc *FormatContext) OutputFormat() *OutputFormat {
return newOutputFormatFromC(fc.c.oformat)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a1e7324262b6b78522e52064daaa7bc87
func (fc *FormatContext) Pb() *IOContext {
// If the io context has been created using the format context's OpenInput() method, we need to
// make sure to return the same go struct as the one stored in classers
if c, ok := classers.get(unsafe.Pointer(fc.c.pb)); ok {
if v, ok := c.(*IOContext); ok {
return v
}
}
return newIOContextFromC(fc.c.pb)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a1e7324262b6b78522e52064daaa7bc87
func (fc *FormatContext) SetPb(i *IOContext) {
fc.c.pb = i.c
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#ac4c0777e54085af2f3f1b27130e2b21b
func (fc *FormatContext) PrivateData() *PrivateData {
return newPrivateDataFromC(fc.c.priv_data)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a2590129e00adfa726ab2033a10e905e9
func (fc *FormatContext) StartTime() int64 {
return int64(fc.c.start_time)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a65f11f94f40f83866ebe651c8ae111cf
func (fc *FormatContext) ProbeScore() int {
return int(fc.c.probe_score)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a5017684cf0a84c990f60c8d50adec144
func (fc *FormatContext) StrictStdCompliance() StrictStdCompliance {
return StrictStdCompliance(fc.c.strict_std_compliance)
}
// https://ffmpeg.org/doxygen/9.0/structAVFormatContext.html#a5017684cf0a84c990f60c8d50adec144
func (fc *FormatContext) SetStrictStdCompliance(strictStdCompliance StrictStdCompliance) {
fc.c.strict_std_compliance = C.int(strictStdCompliance)
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__decoding.html#gac05d61a2b492ae3985c658f34622c19d
func (fc *FormatContext) OpenInput(url string, fmt *InputFormat, d *Dictionary) error {
var urlc *C.char
if url != "" {
urlc = C.CString(url)
defer C.free(unsafe.Pointer(urlc))
}
var dc **C.AVDictionary
if d != nil {
dc = &d.c
}
var fmtc *C.AVInputFormat
if fmt != nil {
fmtc = fmt.c
}
if err := newError(C.avformat_open_input(&fc.c, urlc, fmtc, dc)); err != nil {
return err
}
if pb := fc.Pb(); pb != nil {
classers.set(pb)
}
return nil
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__decoding.html#gae804b99aec044690162b8b9b110236a4
func (fc *FormatContext) CloseInput() {
if fc.c != nil {
// Make sure to clone the classer before freeing the object since
// the C free method may reset the pointer
c := newClonedClasser(fc)
var cpb *ClonedClasser
if pb := fc.Pb(); pb != nil {
cpb = newClonedClasser(pb)
}
C.avformat_close_input(&fc.c)
// Make sure to remove from classers after freeing the object since
// the C free method may use methods needing the classer
if cpb != nil {
classers.del(cpb)
}
if c != nil {
classers.del(c)
}
}
}
// https://ffmpeg.org/doxygen/9.0/demux__utils_8c.html#a29bbc47c9d4d0f26439da347eba9a15a
func (fc *FormatContext) NewChapter() (*Chapter, error) {
ch := (*C.AVChapter)(C.av_mallocz(C.sizeof_AVChapter))
if ch == nil {
return nil, fmt.Errorf("astiav: allocation is nil")
}
if ret := C.av_dynarray_add_nofree(unsafe.Pointer(&fc.c.chapters), (*C.int)(unsafe.Pointer(&fc.c.nb_chapters)), unsafe.Pointer(ch)); ret < 0 {
C.av_free(unsafe.Pointer(ch))
return nil, newError(ret)
}
return newChapterFromC(ch), nil
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__core.html#gab31f7c7c99dcadead38e8e83e0fdb828
func (fc *FormatContext) NewProgram(id int) *Program {
return newProgramFromC(C.av_new_program(fc.c, C.int(id)), fc)
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__core.html#gaf2c94216a6a19144e86cac843a0a4409
func (fc *FormatContext) NewStream(c *Codec) *Stream {
var cc *C.AVCodec
if c != nil {
cc = c.c
}
return newStreamFromC(C.avformat_new_stream(fc.c, cc))
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__decoding.html#gad42172e27cddafb81096939783b157bb
func (fc *FormatContext) FindStreamInfo(d *Dictionary) error {
var dc **C.AVDictionary
if d != nil {
dc = &d.c
}
return newError(C.avformat_find_stream_info(fc.c, dc))
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__decoding.html#ga4fdb3084415a82e3810de6ee60e46a61
func (fc *FormatContext) ReadFrame(p *Packet) error {
var pc *C.AVPacket
if p != nil {
pc = p.c
}
return newError(C.av_read_frame(fc.c, pc))
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__decoding.html#gaa23f7619d8d4ea0857065d9979c75ac8
func (fc *FormatContext) SeekFrame(streamIndex int, timestamp int64, f SeekFlags) error {
return newError(C.av_seek_frame(fc.c, C.int(streamIndex), C.int64_t(timestamp), C.int(f)))
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__decoding.html#gaa03a82c5fd4fe3af312d229ca94cd6f3
func (fc *FormatContext) Flush() error {
return newError(C.avformat_flush(fc.c))
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__encoding.html#ga18b7b10bb5b94c4842de18166bc677cb
func (fc *FormatContext) WriteHeader(d *Dictionary) error {
var dc **C.AVDictionary
if d != nil {
dc = &d.c
}
return newError(C.avformat_write_header(fc.c, dc))
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__encoding.html#gaa85cc1774f18f306cd20a40fc50d0b36
func (fc *FormatContext) WriteFrame(p *Packet) error {
var pc *C.AVPacket
if p != nil {
pc = p.c
}
return newError(C.av_write_frame(fc.c, pc))
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__encoding.html#ga37352ed2c63493c38219d935e71db6c1
func (fc *FormatContext) WriteInterleavedFrame(p *Packet) error {
var pc *C.AVPacket
if p != nil {
pc = p.c
}
return newError(C.av_interleaved_write_frame(fc.c, pc))
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__encoding.html#ga7f14007e7dc8f481f054b21614dfec13
func (fc *FormatContext) WriteTrailer() error {
return newError(C.av_write_trailer(fc.c))
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__misc.html#gafa6fbfe5c1bf6792fd6e33475b6056bd
func (fc *FormatContext) GuessSampleAspectRatio(s *Stream, f *Frame) Rational {
var cf *C.AVFrame
if f != nil {
cf = f.c
}
return newRationalFromC(C.av_guess_sample_aspect_ratio(fc.c, s.c, cf))
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__misc.html#ga698e6aa73caa9616851092e2be15875d
func (fc *FormatContext) GuessFrameRate(s *Stream, f *Frame) Rational {
var cf *C.AVFrame
if f != nil {
cf = f.c
}
return newRationalFromC(C.av_guess_frame_rate(fc.c, s.c, cf))
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__misc.html#gaa2a7353a6bb0c8726797abd56b176af0
func (fc *FormatContext) SDPCreate() (string, error) {
return stringFromC(1024, func(buf *C.char, size C.size_t) error {
fccs := []*C.AVFormatContext{fc.c}
return newError(C.av_sdp_create(&fccs[0], C.int(len(fccs)), buf, C.int(size)))
})
}
// https://ffmpeg.org/doxygen/9.0/avformat_8c.html#a8d4609a8f685ad894c1503ffd1b610b4
func (fc *FormatContext) FindBestStream(mt MediaType, wantedStreamIndex, relatedStreamIndex int) (*Stream, *Codec, error) {
// Find best stream
var cCodec *C.AVCodec
ret := C.av_find_best_stream(fc.c, C.enum_AVMediaType(mt), C.int(wantedStreamIndex), C.int(relatedStreamIndex), &cCodec, 0)
if err := newError(ret); err != nil {
return nil, nil, err
}
// Loop through streams
for _, s := range fc.Streams() {
if s.Index() == int(ret) {
return s, newCodecFromC(cCodec), nil
}
}
return nil, nil, fmt.Errorf("astiav: no stream with index %d", ret)
}
// https://ffmpeg.org/doxygen/9.0/group__lavf__misc.html#gae2645941f2dc779c307eb6314fd39f10
func (fc *FormatContext) Dump(streamIndex int, url string, isOutput bool) {
curl := (*C.char)(nil)
if len(url) > 0 {
curl = C.CString(url)
defer C.free(unsafe.Pointer(curl))
}
cisOutput := 0
if isOutput {
cisOutput = 1
}
C.av_dump_format(fc.c, C.int(streamIndex), curl, C.int(cisOutput))
}
var formatContextIOOpeners = newFormatContextIOOpenerPool()
type formatContextIOOpenerPool struct {
m sync.Mutex
p map[unsafe.Pointer]*formatContextIOOpenerPoolItem
}
type formatContextIOOpenerPoolItem struct {
closeFunc FormatContextIOCloseFunc
openFunc FormatContextIOOpenFunc
pbs map[*C.AVIOContext]*IOContext
}
func newFormatContextIOOpenerPool() *formatContextIOOpenerPool {
return &formatContextIOOpenerPool{p: make(map[unsafe.Pointer]*formatContextIOOpenerPoolItem)}
}
func newFormatContextIOOpenerPoolItem(openFunc FormatContextIOOpenFunc, closeFunc FormatContextIOCloseFunc) *formatContextIOOpenerPoolItem {
return &formatContextIOOpenerPoolItem{
closeFunc: closeFunc,
openFunc: openFunc,
pbs: make(map[*C.AVIOContext]*IOContext),
}
}
func (p *formatContextIOOpenerPool) setIOOpener(f *FormatContext, openFunc FormatContextIOOpenFunc, closeFunc FormatContextIOCloseFunc) {
p.m.Lock()
defer p.m.Unlock()
p.p[f.c.opaque] = newFormatContextIOOpenerPoolItem(openFunc, closeFunc)
}
func (p *formatContextIOOpenerPool) setIOContext(cf *C.AVFormatContext, pb *IOContext) {
p.m.Lock()
defer p.m.Unlock()
i, ok := p.p[cf.opaque]
if !ok {
return
}
i.pbs[pb.c] = pb
}
func (p *formatContextIOOpenerPool) getCloseFunc(cf *C.AVFormatContext, cpb *C.AVIOContext) (FormatContextIOCloseFunc, *IOContext, bool) {
p.m.Lock()
defer p.m.Unlock()
i, ok := p.p[cf.opaque]
if !ok {
return nil, nil, false
}
c, ok := i.pbs[cpb]
return i.closeFunc, c, ok
}
func (p *formatContextIOOpenerPool) getOpenFunc(cf *C.AVFormatContext) (FormatContextIOOpenFunc, bool) {
p.m.Lock()
defer p.m.Unlock()
i, ok := p.p[cf.opaque]
return i.openFunc, ok
}
func (p *formatContextIOOpenerPool) del(f *FormatContext) {
p.m.Lock()
defer p.m.Unlock()
delete(p.p, f.c.opaque)
}
//export goAstiavFormatContextIOOpen
func goAstiavFormatContextIOOpen(cf *C.AVFormatContext, cpb **C.AVIOContext, curl *C.char, cflags C.int, cdict **C.AVDictionary) C.int {
openFunc, ok := formatContextIOOpeners.getOpenFunc(cf)
if !ok {
return C.AVERROR_UNKNOWN
}
pb, err := openFunc(C.GoString(curl), IOContextFlags(cflags), newDictionaryFromC(*cdict))
if err != nil {
var e Error
if errors.As(err, &e) {
return C.int(e)
}
return C.AVERROR_UNKNOWN
}
formatContextIOOpeners.setIOContext(cf, pb)
*cpb = pb.c
return 0
}
//export goAstiavFormatContextIOClose
func goAstiavFormatContextIOClose(cf *C.AVFormatContext, cpb *C.AVIOContext) C.int {
closeFunc, pb, ok := formatContextIOOpeners.getCloseFunc(cf, cpb)
if !ok {
return C.AVERROR_UNKNOWN
}
if err := closeFunc(pb); err != nil {
var e Error
if errors.As(err, &e) {
return C.int(e)
}
return C.AVERROR_UNKNOWN
}
return 0
}