-
Notifications
You must be signed in to change notification settings - Fork 6
perfect: 通过 cgo.Handle 传递回调函数,减少读写锁开销 #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b3ec17d
c768dec
246dd83
e3c81ac
12db156
82cb8c3
b24bac4
07835cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -11,7 +11,7 @@ static int frame_get_height(struct Frame* frame) { return frame->height; } | |||||
| */ | ||||||
| import "C" | ||||||
| import ( | ||||||
| "sync" | ||||||
| "runtime/cgo" | ||||||
| "unsafe" | ||||||
| ) | ||||||
|
|
||||||
|
|
@@ -87,25 +87,17 @@ type Callback interface { | |||||
| } | ||||||
|
|
||||||
| type Player struct { | ||||||
| handle C.crp_handle | ||||||
| callbackId int | ||||||
| handle C.crp_handle | ||||||
| cbHandle cgo.Handle | ||||||
| } | ||||||
|
|
||||||
| var mutex sync.RWMutex | ||||||
| var callbacks = make(map[int]Callback) | ||||||
| var lastId = 0 | ||||||
|
|
||||||
| //export goCallback | ||||||
| func goCallback(event C.enum_Event, data unsafe.Pointer, userData unsafe.Pointer) { | ||||||
| id := int(uintptr(userData)) | ||||||
| mutex.RLock() | ||||||
| callback, ok := callbacks[id] | ||||||
| mutex.RUnlock() | ||||||
| if !ok { | ||||||
| return | ||||||
| } | ||||||
|
|
||||||
| if event == C.CRP_EV_NEW_FRAME { | ||||||
| callback := cgo.Handle(uintptr(userData)).Value().(Callback) | ||||||
|
|
||||||
| switch event { | ||||||
| case C.CRP_EV_NEW_FRAME: | ||||||
| frame := (*C.struct_Frame)(data) | ||||||
| height := C.frame_get_height(frame) | ||||||
| callback.OnFrame(false, Frame{ | ||||||
|
|
@@ -122,7 +114,7 @@ func goCallback(event C.enum_Event, data unsafe.Pointer, userData unsafe.Pointer | |||||
| [4]int{int(frame.stride[0]), int(frame.stride[1]), int(frame.stride[2]), int(frame.stride[3])}, | ||||||
| uint64(frame.pts), | ||||||
| }) | ||||||
| } else if event == C.CRP_EV_NEW_AUDIO { | ||||||
| case C.CRP_EV_NEW_AUDIO: | ||||||
| frame := (*C.struct_Frame)(data) | ||||||
| callback.OnFrame(true, Frame{ | ||||||
| 0, 0, | ||||||
|
|
@@ -138,10 +130,10 @@ func goCallback(event C.enum_Event, data unsafe.Pointer, userData unsafe.Pointer | |||||
| [4]int{int(frame.stride[0]), int(frame.stride[1]), int(frame.stride[2]), int(frame.stride[3])}, | ||||||
| uint64(frame.pts), | ||||||
| }) | ||||||
| } else if event == C.CRP_EV_VIDEO_EXTRADATA || event == C.CRP_EV_AUDIO_EXTRADATA { | ||||||
| case C.CRP_EV_VIDEO_EXTRADATA, C.CRP_EV_AUDIO_EXTRADATA: | ||||||
| ed := (*C.struct_ExtraData)(data) | ||||||
| callback.OnEvent(Event(event), C.GoBytes(unsafe.Pointer(ed.data), C.int(ed.size))) | ||||||
| } else { | ||||||
| default: | ||||||
| callback.OnEvent(Event(event), int64(uintptr(data))) | ||||||
| } | ||||||
| } | ||||||
|
|
@@ -154,9 +146,10 @@ func (player *Player) Destroy() { | |||||
| C.crp_destroy(player.handle) | ||||||
| player.handle = nil | ||||||
|
|
||||||
| mutex.Lock() | ||||||
| delete(callbacks, player.callbackId) | ||||||
| mutex.Unlock() | ||||||
| if player.cbHandle != 0 { | ||||||
| player.cbHandle.Delete() | ||||||
| player.cbHandle = 0 | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| func (player *Player) Auth(username, password string, isMd5 bool) { | ||||||
|
|
@@ -191,14 +184,12 @@ func (player *Player) Play(url string, option Option, callback Callback) { | |||||
| timeout: C.int64_t(option.Timeout), | ||||||
| } | ||||||
|
|
||||||
| mutex.Lock() | ||||||
| id := lastId | ||||||
| player.callbackId = id | ||||||
| callbacks[id] = callback | ||||||
| lastId += 1 | ||||||
| mutex.Unlock() | ||||||
| if player.cbHandle != 0 { | ||||||
| player.cbHandle.Delete() | ||||||
| } | ||||||
| player.cbHandle = cgo.NewHandle(callback) | ||||||
|
|
||||||
| C.crp_play(player.handle, curl, &coption, C.crp_callback(C.goCallback), unsafe.Pointer(uintptr(id))) | ||||||
| C.crp_play(player.handle, curl, &coption, C.crp_callback(C.goCallback), unsafe.Pointer(player.cbHandle)) | ||||||
|
Comment on lines
+187
to
+192
|
||||||
| C.crp_play(player.handle, curl, &coption, C.crp_callback(C.goCallback), unsafe.Pointer(player.cbHandle)) | |
| C.crp_play(player.handle, curl, &coption, C.crp_callback(C.goCallback), unsafe.Pointer(uintptr(player.cbHandle))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cgo.Handle(uintptr(userData)).Value().(Callback)will panic ifuserDataisnil/0, if the handle has already been deleted, or if the stored value is a nil interface / wrong type. Panics crossing the cgo boundary will crash the process. Add guards (e.g., return early onuserData == nil, use a safe type assertion, and consider recovering fromruntime/cgo: misuse of an invalid Handle).