forked from csnewman/ffmpeg-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlog.go
149 lines (113 loc) · 2.67 KB
/
log.go
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
package ffmpeg
import (
"fmt"
"log/slog"
"strings"
"sync"
"unsafe"
)
/*
#include <libavutil/log.h>
void ffg_set_log();
typedef const char* (*itemNameFunc) (void* ctx);
const char* invokeItemNameFunc(itemNameFunc f, void* ctx);
*/
import "C"
type LogCallback func(ctx *LogCtx, level int, msg string)
var activeLogCallback LogCallback //nolint:gochecknoglobals
//export ffgLogCallback
func ffgLogCallback(ctxPtr unsafe.Pointer, level int, msgPtr *C.char) {
var ctx *LogCtx
if ctxPtr != nil {
ctx = &LogCtx{
ptr: ctxPtr,
}
}
msgWrapper := wrapCStr(msgPtr)
msg := msgWrapper.String()
msgWrapper.Free()
if activeLogCallback != nil {
activeLogCallback(ctx, level, msg)
}
}
// AVLogSetCallback wraps av_log_set_callback.
/*
Set the logging callback
@note The callback must be thread safe, even if the application does not use
threads itself as some codecs are multithreaded.
@see av_log_default_callback
@param callback A logging function with a compatible signature.
*/
func AVLogSetCallback(cb LogCallback) {
activeLogCallback = cb
C.ffg_set_log()
}
// ItemName gets the item_name field.
func (s *AVClass) ItemName() func(pointer unsafe.Pointer) *CStr {
fp := s.ptr.item_name
return func(pointer unsafe.Pointer) *CStr {
value := C.invokeItemNameFunc(fp, pointer)
return wrapCStr(value)
}
}
type LogCtx struct {
ptr unsafe.Pointer
}
func (c *LogCtx) RawPtr() unsafe.Pointer {
return c.ptr
}
func (c *LogCtx) Class() *AVClass {
classPtr := *(**C.AVClass)(c.ptr)
if classPtr == nil {
return nil
}
return &AVClass{
ptr: classPtr,
}
}
func SLogAdapter(logger *slog.Logger) LogCallback {
l := &slogLogger{
logger: logger,
}
return l.callback
}
type slogLogger struct {
logger *slog.Logger
mu sync.Mutex
sb strings.Builder
}
func (l *slogLogger) callback(ctx *LogCtx, level int, msg string) {
l.mu.Lock()
defer l.mu.Unlock()
for {
before, after, found := strings.Cut(msg, "\n")
msg = after
l.sb.WriteString(before)
if !found {
break
}
scope := "global"
if ctx != nil {
class := ctx.Class()
scope = class.ItemName()(ctx.RawPtr()).String()
}
if level >= 0 {
level &= 0xff
}
printMsg := l.sb.String()
l.sb.Reset()
switch level {
case AVLogQuiet:
case AVLogPanic:
panic(fmt.Sprintf("FFmpeg log scope=%v log=%v", scope, printMsg))
case AVLogFatal, AVLogError:
l.logger.Error("FFmpeg Log", "scope", scope, "log", printMsg)
case AVLogWarning:
l.logger.Warn("FFmpeg Log", "scope", scope, "log", printMsg)
case AVLogDebug, AVLogTrace:
l.logger.Debug("FFmpeg Log", "scope", scope, "log", printMsg)
default:
l.logger.Info("FFmpeg Log", "scope", scope, "log", printMsg)
}
}
}