【发布时间】:2019-07-02 03:56:26
【问题描述】:
我有一个对音频数据进行分析的 C++ 库和一个 C API。其中一个 C API 函数采用 const int16_t* 指向数据的指针并返回分析结果。
我正在尝试为这个 API 构建一个 Python 接口,并且大部分接口都在工作,但是我无法让 ctypes 指针用作这个函数的参数。由于 C 端的指针指向const,因此我觉得应该可以使用任何连续数据使其正常工作。但是,以下方法不起作用:
import ctypes
import wave
_native_lib = ctypes.cdll.LoadLibrary('libsound.so')
_native_function = _native_lib.process_sound_data
_native_function.argtypes = [ctypes.POINTER(ctypes.c_int16),
ctypes.c_size_t]
_native_function.restype = ctypes.c_int
wav_path = 'hello.wav'
with wave.open(wav_path, mode='rb') as wav_file:
wav_bytes = wav_file.readframes(wav_file.getnframes())
data_start = ctypes.POINTER(ctypes.c_int16).from_buffer(wav_bytes) # ERROR: data is immutable
_native_function(data_start, len(wav_bytes)//2)
手动将wav_bytes 复制到bytearray 允许构造指针,但会导致本机代码出现段错误,表明它接收到的地址是错误的(它通过单元测试并使用从C++ 读取的数据)。通过获取正确的地址来解决这个问题在技术上可以解决问题,但我觉得有更好的方法。
当然可以只获取一些数据的地址并保证它是正确的格式并且不会被更改吗?我宁愿不必将我所有以 Python 方式存储的音频数据深度复制为 ctypes 格式,因为如果我能获得指向它们的指针,这些字节可能就在某处!
理想情况下,我希望能够做这样的事情
data_start = cast_to(address_of(data[0]), c_int16_pointer)
_native_function(data_start, len(data))
这将适用于任何具有[0] 和len 的东西。有没有办法在 ctypes 中做这样的事情?如果没有,是否有技术原因导致它不可能,还有其他我应该使用的东西吗?
【问题讨论】:
-
为 _native_function 指定 argtypes 和 restype。 stackoverflow.com/questions/52268294/…stackoverflow.com/questions/53182796/….
-
@CristiFati 我在代码加载
_native_function中进行了编辑。我的问题不是如何声明这个函数,而是如何将 Python 数据转换为适合它的参数。 -
您对段错误的评论很有趣。您在 Windows 中看到了吗?你在 macOS 或 Linux 下试过吗?我觉得 question I asked 可能与您看到的内容相关联。
-
@MatthewWalker 不幸的是,我只在 Linux 上进行了测试,所以我不知道在 Windows 上会发生什么。实际上,我认为我也从未在 Linux 上修复过那个狡猾的副本,因为我最终只是将其转换为。说实话,整个 ctypes API 有点乱。而且恐怕我不知道您如何调试您的问题,而不是使用 -g 编译您自己的 CPython 并在其上运行 GDB。