我想调用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 *
点的长度,其次,我不需要任何复制,我只需要一个简单的转换。
答案 0 :(得分:5)
我不知道你在哪里得到了void*
,但是在大多数情况下,如果你在Vala中有一个指针,你做错了。有一些例外,主要是因为你使用libxml,但它们很少而且很少。您应该查看创建void*
的代码并考虑是否有更好的方法,例如new uint8[x]
而不是malloc(x)
。
将void*
转换为uint8[]
只需要强制转换,但长度将设置为-1。 Gdk.Pixbuf.from_data
实际上并不需要长度(它根据height
和rowstride
计算),所以这不应该是个问题。但是,一般来说,您可能希望执行类似
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
取得所有权,因此无法绕过副本。