如回溯所示,将nonetype传递给media_read_cb。代码中的问题似乎是media_open_cb函数。如果在media_new_callbacks函数中将此回调替换为None,则将不会调用该回调,并且会使用适当的不透明指针来调用media_read_cb。
这对我来说有点晦涩。如果open_cb设置为None,vlc将调用其默认的open_cb,默认情况下,它将将size_pointer设置为maxsize,将data_pointer设置为不透明(与您的功能相同)。显然,设置指针的值时代码中出现错误。我也不知道如何解决这个问题,因为我也是ctypes的新手。
media = instance.media_new_callbacks(None, callbacks['read'], callbacks['seek'], callbacks['close'], ctypes.byref(ctypes.py_object(stream)))
成功调用了media_read_cb。但是,python然后在以下位置崩溃:
stream = ctypes.cast(opaque, ctypes.py_object).value
我也不知道如何解决这个问题,但是有一个解决方法。您可以将流变量设置为全局变量,因此可以自己保留指针,而不必依赖ctypes东西。
写入缓冲区似乎也不起作用,因为缓冲区将作为字符串传递给media_read_cb。由于字符串在python中是不可变的,因此失败。一种解决方法是将CFUNCTYPE更改为包含ctypes.POINTER,将其更改为c_char而不是普通的c_char_p(python中的字符串)。然后,您可以在迭代过程中使用流中的字节填充内存区域。
应用这些更改,您的代码如下所示:
import ctypes
import io
import sys
import time
import vlc
MediaOpenCb = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(ctypes.c_uint64))
MediaReadCb = ctypes.CFUNCTYPE(ctypes.c_ssize_t, ctypes.c_void_p, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t)
MediaSeekCb = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_uint64)
MediaCloseCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p)
stream=None
def media_open_cb(opaque, data_pointer, size_pointer):
data_pointer.value = opaque
size_pointer.contents.value = sys.maxsize
return 0
def media_read_cb(opaque, buffer, length):
new_data = stream.read(length)
for i in range(len(new_data)):
buffer[i]=new_data[i]
return len(new_data)
def media_seek_cb(opaque, offset):
stream.seek(offset)
return 0
def media_close_cb(opaque):
stream.close()
callbacks = {
'open': MediaOpenCb(media_open_cb),
'read': MediaReadCb(media_read_cb),
'seek': MediaSeekCb(media_seek_cb),
'close': MediaCloseCb(media_close_cb)
}
def main(path):
global stream
stream = open(path, 'rb')
instance = vlc.Instance('-vvv')
player = instance.media_player_new()
media = instance.media_new_callbacks(None, callbacks['read'], callbacks['seek'], callbacks['close'], ctypes.byref(ctypes.py_object(stream)))
player.set_media(media)
player.play()
while True:
time.sleep(1)
if __name__ == '__main__':
try:
path = sys.argv[1]
except IndexError:
print('Usage: {0} <path>'.format(__file__))
sys.exit(1)
main(path)
它成功运行!
当然,与其使用全局变量,不如将所有这些都包装在python类中。
我想出了如何正确设置data_pointer。这是代码:
import ctypes
import io
import sys
import time
import vlc
MediaOpenCb = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(ctypes.c_uint64))
MediaReadCb = ctypes.CFUNCTYPE(ctypes.c_ssize_t, ctypes.c_void_p, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t)
MediaSeekCb = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_uint64)
MediaCloseCb = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p)
def media_open_cb(opaque, data_pointer, size_pointer):
data_pointer.contents.value = opaque
size_pointer.contents.value = sys.maxsize
return 0
def media_read_cb(opaque, buffer, length):
stream=ctypes.cast(opaque,ctypes.POINTER(ctypes.py_object)).contents.value
new_data = stream.read(length)
for i in range(len(new_data)):
buffer[i]=new_data[i]
return len(new_data)
def media_seek_cb(opaque, offset):
stream=ctypes.cast(opaque,ctypes.POINTER(ctypes.py_object)).contents.value
stream.seek(offset)
return 0
def media_close_cb(opaque):
stream=ctypes.cast(opaque,ctypes.POINTER(ctypes.py_object)).contents.value
stream.close()
callbacks = {
'open': MediaOpenCb(media_open_cb),
'read': MediaReadCb(media_read_cb),
'seek': MediaSeekCb(media_seek_cb),
'close': MediaCloseCb(media_close_cb)
}
def main(path):
stream = open(path, 'rb')
instance = vlc.Instance()
player = instance.media_player_new()
media = instance.media_new_callbacks(callbacks['open'], callbacks['read'], callbacks['seek'], callbacks['close'], ctypes.cast(ctypes.pointer(ctypes.py_object(stream)), ctypes.c_void_p))
player.set_media(media)
player.play()
while True:
time.sleep(1)
if __name__ == '__main__':
try:
path = sys.argv[1]
except IndexError:
print('Usage: {0} <path>'.format(__file__))
sys.exit(1)
main(path)