我想调用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], ...);
Run Code Online (Sandbox Code Playgroud)
上面的转换不起作用,因为vala生成C代码,该代码将数据复制memory到新创建的数组但长度不正确.首先,显然vala本身不知道void *点的长度,其次,我不需要任何复制,我只需要一个简单的转换.
我不知道你在哪里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;
Run Code Online (Sandbox Code Playgroud)
由于某些功能确实需要长度.许多人也不检查使用它的长度参数,这意味着无效长度很容易触发段错误.基本上,这是一个很好的习惯,它通常比检查每个参数更容易,看看是否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, ...);
Run Code Online (Sandbox Code Playgroud)
但请注意,在传递数据时,您仍然会得到一份副本Gdk.Pixbuf.from_data.Gdk.Pixbuf.from_data除非您可以转让原始数据的所有权,否则除非取得所有权,否则无法复制副本.