/// <summary> /// 从指向非托管内存空间的WebPData指针解码 /// </summary> /// <param name="webPDataPointer"></param> /// <returns></returns> public WebPAnimation DecodeFromWebPDataPointer(IntPtr webPDataPointer) { //解调WebP数据以提取所有帧、ICC配置文件和EXIF / XMP元数据 IntPtr demux = LibwebpdemuxUtils.WebPDemuxInternal(webPDataPointer, 0, IntPtr.Zero, Version); //创建迭代器,用来遍历动画的每一帧 WebPIterator iter = new WebPIterator(); //创建指向迭代器的指针 IntPtr ptrIter = Marshal.AllocHGlobal(Marshal.SizeOf(iter)); //给迭代器指针赋初值 Marshal.StructureToPtr(iter, ptrIter, true); //初始化WebP动画结构体,这是本函数要返回的结果 WebPAnimation animation = new WebPAnimation(); //遍历所有帧 if (LibwebpdemuxUtils.WebPDemuxGetFrame(demux, 1, ptrIter) != 0) { //如果成功获取了第一帧,就创建一个简单解码器 SimpleDecoder simpleDecoder = new SimpleDecoder(); do { //解引用迭代器指针,恢复出迭代器对象 iter = Marshal.PtrToStructure <WebPIterator>(ptrIter); //创建一个动画帧对象 WebPAnimationFrame frame = new WebPAnimationFrame(); //将迭代器中获得的数据存入动画帧对象中 frame.Complete = Convert.ToBoolean(iter.complete); frame.Duration = iter.duration; frame.HasAlpha = Convert.ToBoolean(iter.has_alpha); frame.Height = iter.height; frame.Width = iter.width; frame.XOffset = iter.x_offset; frame.YOffset = iter.y_offset; frame.Image = simpleDecoder.DecodeFromPointer(iter.fragment.bytes, (long)iter.fragment.size); //将动画帧添加到动画对象中 animation.Frames.Add(frame); } while (LibwebpdemuxUtils.WebPDemuxNextFrame(ptrIter) != 0); //释放迭代器 LibwebpdemuxUtils.WebPDemuxReleaseIterator(ptrIter); } //释放之前申请的非托管内存空间 Marshal.FreeHGlobal(ptrIter); //指针置为0 ptrIter = IntPtr.Zero; //返回动画对象 return(animation); }
private unsafe List <(Texture2D, int)> LoadAnimation2(string loadPath) { List <ValueTuple <Texture2D, int> > ret = new List <ValueTuple <Texture2D, int> >(); TextAsset textasset = Resources.Load <TextAsset>(loadPath); byte[] bytes = textasset.bytes; WebPDecoderConfig config = new WebPDecoderConfig(); if (NativeLibwebp.WebPInitDecoderConfig(&config) == 0) { throw new Exception("WebPInitDecoderConfig failed. Wrong version?"); } WebPIterator iter = new WebPIterator(); fixed(byte *p = bytes) { WebPData webpdata = new WebPData { bytes = p, size = new UIntPtr((uint)bytes.Length) }; WebPDemuxer *webPDemuxer = NativeLibwebpdemux.WebPDemuxInternal(&webpdata, 0, (WebPDemuxState *)IntPtr.Zero, NativeLibwebpdemux.WEBP_DEMUX_ABI_VERSION); VP8StatusCode result = NativeLibwebp.WebPGetFeatures(webpdata.bytes, webpdata.size, &config.input); if (result != VP8StatusCode.VP8_STATUS_OK) { throw new Exception(string.Format("Failed WebPGetFeatures with error {0}.", result.ToString())); } int height = config.input.height; int width = config.input.height; config.options.bypass_filtering = 0; config.options.use_threads = 1; config.options.no_fancy_upsampling = 0; config.options.use_cropping = 0; config.options.use_scaling = 1; config.options.scaled_width = width; config.options.scaled_height = height; config.options.flip = 1; config.options.dithering_strength = 0; config.output.colorspace = WEBP_CSP_MODE.MODE_RGBA; config.output.width = width; config.output.height = height; //byte[] bbb = new byte[width * height]; //fixed (byte* ppp = bbb) //{ // config.output.u.RGBA.rgba = (IntPtr)ppp; //} //config.output.u.RGBA.stride = width * 4; //config.output.u.RGBA.size = (UIntPtr)(width * height); //config.output.is_external_memory = 1; //config.output.is_external_memory = 1; int success = NativeLibwebpdemux.WebPDemuxGetFrame(webPDemuxer, 1, &iter); if (success != 1) { return(ret); } int timestamp = 0; int size = width * height * 4; do { WebPData frame = iter.fragment; VP8StatusCode status = NativeLibwebp.WebPDecode(frame.bytes, frame.size, &config); if (status != VP8StatusCode.VP8_STATUS_OK) { Debug.LogError(status); break; } Texture2D texture = Texture2DExt.CreateWebpTexture2D(width, height, isUseMipmap: false, isLinear: false); texture.LoadRawTextureData((IntPtr)config.output.u.RGBA.rgba, size); texture.Apply(updateMipmaps: false, makeNoLongerReadable: true); timestamp += iter.duration; ret.Add((texture, timestamp)); }while (NativeLibwebpdemux.WebPDemuxNextFrame(&iter) == 1); NativeLibwebpdemux.WebPDemuxDelete(webPDemuxer); NativeLibwebpdemux.WebPDemuxReleaseIterator(&iter); } return(ret); }
public static extern void WebPDemuxReleaseIterator(ref WebPIterator dec);
private unsafe List <(Texture2D, int)> LoadAnimation2(string loadPath) { List <ValueTuple <Texture2D, int> > ret = new List <ValueTuple <Texture2D, int> >(); TextAsset textasset = Resources.Load <TextAsset>(loadPath); byte[] bytes = textasset.bytes; var config = new WebPDecoderConfig(); if (Decode.WebPInitDecoderConfig(ref config) == 0) { throw new Exception("WebPInitDecoderConfig failed. Wrong version?"); } var iter = new WebPIterator(); IntPtr webpDataPtr = Marshal.AllocHGlobal(sizeof(WebPData)); IntPtr configPtr = Marshal.AllocHGlobal(Marshal.SizeOf(config)); IntPtr iterPtr = Marshal.AllocHGlobal(Marshal.SizeOf(iter)); try { fixed(byte *p = bytes) { IntPtr ptr = (IntPtr)p; WebPData webpdata = new WebPData { bytes = ptr, size = new UIntPtr((uint)bytes.Length) }; Marshal.StructureToPtr(webpdata, webpDataPtr, false); Marshal.StructureToPtr(config, configPtr, false); Marshal.StructureToPtr(iter, iterPtr, false); IntPtr webPDemuxer = Demux.WebPDemuxInternal(webpDataPtr, 0, (IntPtr)0, Demux.WEBP_DEMUX_ABI_VERSION); VP8StatusCode result = Decode.WebPGetFeatures(webpdata.bytes, webpdata.size, ref config.input); if (result != VP8StatusCode.VP8_STATUS_OK) { throw new Exception(string.Format("Failed WebPGetFeatures with error {0}.", result.ToString())); } var height = config.input.height; var width = config.input.height; config.options.bypass_filtering = 0; config.options.use_threads = 1; config.options.no_fancy_upsampling = 0; config.options.use_cropping = 0; config.options.use_scaling = 1; config.options.scaled_width = width; config.options.scaled_height = height; config.options.flip = 1; config.options.dithering_strength = 0; config.output.colorspace = WEBP_CSP_MODE.MODE_RGBA; config.output.width = width; config.output.height = height; //byte[] bbb = new byte[width * height]; //fixed (byte* ppp = bbb) //{ // config.output.u.RGBA.rgba = (IntPtr)ppp; //} //config.output.u.RGBA.stride = width * 4; //config.output.u.RGBA.size = (UIntPtr)(width * height); //config.output.is_external_memory = 1; //config.output.is_external_memory = 1; int success = Demux.WebPDemuxGetFrame(webPDemuxer, 1, ref iter); if (success != 1) { return(ret); } int timestamp = 0; int size = width * height * 4; do { WebPData frame = iter.fragment; VP8StatusCode status = Decode.WebPDecode(frame.bytes, frame.size, ref config); if (status != VP8StatusCode.VP8_STATUS_OK) { Debug.LogError(status); break; } var texture = new Texture2D(width, height, TextureFormat.RGBA32, mipChain: false, linear: false); texture.LoadRawTextureData(config.output.u.RGBA.rgba, size); texture.Apply(updateMipmaps: false, makeNoLongerReadable: true); timestamp += iter.duration; ret.Add((texture, timestamp)); }while (Demux.WebPDemuxNextFrame(ref iter) == 1); Demux.WebPDemuxDelete(webPDemuxer); Demux.WebPDemuxReleaseIterator(ref iter); } } finally { Marshal.FreeHGlobal(webpDataPtr); Marshal.FreeHGlobal(configPtr); Marshal.FreeHGlobal(iterPtr); } return(ret); }