vala:如何将 void * 转换为 uint[]?

vala: how to cast void * to uint[]?

我想调用 Gdk.Pixbuf.from_data() 构造函数,以便将来自 GStreamer 的视频帧包装到 pixbuf 中。构造函数接受内存指针为 uint8[]。但是我有一个指向数据开头的 void * 变量 (Gst.Video.Frame.data[0])。我知道 uint8[] 不仅仅是一个指针,而是一种知道内存从哪里开始以及它跨越多远的类型。但是对于 Gdk.Pixbuf.from_data() 这并不重要,因为函数的 C 签名只接受 const guchar * 并且长度是从步幅和高度等其他参数推断出来的。

那么...如何正确地将我的 void * 指针包装到 uint[] 数组中?

Video.Frame frame = {};
...
var pixbuf = new Gdk.Pixbuf.from_data((uint8[])frame.data[0], ...);

上面的转换不起作用,因为 vala 生成的 C 代码将数据从 memory 复制到新创建的数组,但长度不正确。首先,很明显vala本身不知道void *指向的长度,其次,我不需要任何复制,我只需要一个简单的转换。

我不知道你从哪里得到 void*,但在大多数情况下,如果你在 Vala 中有一个指针,那你就做错了。也有例外,主要是在您使用 libxml 时,但它们很少见。您应该查看创建 void* 的代码,并考虑是否有更好的方法,例如 new uint8[x] 而不是 malloc(x).

void* 转换为 uint8[] 只需要一次转换,但长度将设置为 -1。 Gdk.Pixbuf.from_data 实际上不需要长度(它是根据 heightrowstride 计算的),所以这应该不是问题。但是,一般来说,您可能想做类似

的事情
unowned uint8[] data = (uint8[]) memory;
data.length = whatever;

因为有些函数确实需要长度。许多人也不检查使用它的长度参数,这意味着无效的长度很容易触发段错误。基本上,这是一个养成的好习惯,而且通常比检查每个参数以查看是否设置了 array_length = false CCode 属性更容易。

Vala 生成副本的原因是 Gdk.Pixbuf.from_data 取得了数据的所有权。您需要告诉 Vala 转移数据的所有权(使用 (owned))。

综合起来:

unowned uint8[] data = (uint8[]) memory;
data.length = whatever;
Gdk.Pixbuf pb = new Gdk.Pixbuf.from_data(data, ...);

但请注意,当数据传递给 Gdk.Pixbuf.from_data 时,您最终仍会得到一份副本。由于 Gdk.Pixbuf.from_data 取得了所有权,因此无法绕过副本,除非您可以转让原始数据的所有权。