浏览代码

Merge pull request #221 from UnityTech/gif

Fix GIF memory overflow problem.
/main
GitHub 6 年前
当前提交
02d52465
共有 4 个文件被更改,包括 64 次插入104 次删除
  1. 23
      Runtime/painting/image_stream.cs
  2. 10
      Runtime/ui/painting/GifDecoder.cs
  3. 8
      Runtime/ui/painting/codec.cs
  4. 127
      Runtime/ui/painting/codec_gif.cs

23
Runtime/painting/image_stream.cs


}
void _decodeNextFrameAndSchedule() {
this._codec.getNextFrame().Then(frame => {
this._nextFrame = frame;
var frame = this._codec.getNextFrame();
this._nextFrame = frame;
if (this._codec.frameCount == 1) {
this._emitFrame(new ImageInfo(image: this._nextFrame.image, scale: this._scale));
return;
}
if (this._codec.frameCount == 1) {
this._emitFrame(new ImageInfo(image: this._nextFrame.image, scale: this._scale));
return;
}
SchedulerBinding.instance.scheduleFrameCallback(this._handleAppFrame);
},
ex => {
this.reportError(
context: "resolving an image frame",
exception: ex,
informationCollector: this._informationCollector,
silent: true
);
});
SchedulerBinding.instance.scheduleFrameCallback(this._handleAppFrame);
}
void _emitFrame(ImageInfo imageInfo) {

10
Runtime/ui/painting/GifDecoder.cs


this._gct = this._readColorTable(this._gctSize);
this._bgColor = this._gct[this._bgIndex];
}
this._currentFrame = new GifFrame {
bytes = new byte[this._width * this._height * sizeof(int)],
delay = 0
};
}
/**

this._setPixels(); // transfer pixel data to image
var bytes = new byte[this._width * this._height * sizeof(int)];
Buffer.BlockCopy(this._image, 0, bytes, 0, bytes.Length);
this._currentFrame = new GifFrame {bytes = bytes, delay = this._delay};
Buffer.BlockCopy(this._image, 0, this._currentFrame.bytes, 0, this._currentFrame.bytes.Length);
this._currentFrame.delay = this._delay;
this._frameCount++;
if (this._transparency) {

8
Runtime/ui/painting/codec.cs


public interface Codec : IDisposable {
int frameCount { get; }
int repetitionCount { get; }
IPromise<FrameInfo> getNextFrame();
FrameInfo getNextFrame();
}
public class ImageCodec : Codec {

get { return 0; }
}
public IPromise<FrameInfo> getNextFrame() {
public FrameInfo getNextFrame() {
return Promise<FrameInfo>.Resolved(new FrameInfo {
return new FrameInfo {
});
};
}
public void Dispose() {

127
Runtime/ui/painting/codec_gif.cs


using System;
using System.Collections;
using System.Collections.Generic;
using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;
using UnityEngine;

public GifDecoder.GifFrame gifFrame;
}
readonly List<Promise<FrameData>> _frames;
volatile byte[] _bytes;
volatile int _width;
volatile int _height;
volatile int _frameCount;

volatile Texture2D _texture;
readonly UIWidgetsCoroutine _coroutine;
volatile FrameData _frameData;
volatile Image _image;
volatile GifDecoder _decoder;
volatile MemoryStream _stream;
IEnumerator _coroutine;
this._frames = new List<Promise<FrameData>>();
this._width = 0;
this._height = 0;
this._coroutine = Window.instance.startBackgroundCoroutine(
this._startDecoding(bytes, Window.instance));
this._bytes = bytes;
this._coroutine = this._startDecoding();
this._decoder = new GifDecoder();
this._stream = new MemoryStream(this._bytes);
this._frameData = new FrameData() {
frameInfo = new FrameInfo()
};
IEnumerator _startDecoding(byte[] bytes, Window window) {
var bytesStream = new MemoryStream(bytes);
IEnumerator _startDecoding() {
this._stream.Seek(0, SeekOrigin.Begin);
var gifDecoder = new GifDecoder();
if (gifDecoder.read(bytesStream) != GifDecoder.STATUS_OK) {
if (this._decoder.read(this._stream) != GifDecoder.STATUS_OK) {
this._width = gifDecoder.frameWidth;
this._height = gifDecoder.frameHeight;
this._width = this._decoder.frameWidth;
this._height = this._decoder.frameHeight;
if (this._texture == null) {
this._texture = new Texture2D(this._width, this._height, TextureFormat.BGRA32, false);
this._texture.hideFlags = HideFlags.HideAndDontSave;
this._image = new Image(this._texture);
this._frameData.frameInfo.image = this._image;
}
this._frameData.gifFrame = this._decoder.currentFrame;
D.assert(this._frameData.gifFrame != null);
yield return null;
if (gifDecoder.nextFrame() != GifDecoder.STATUS_OK) {
if (this._decoder.nextFrame() != GifDecoder.STATUS_OK) {
if (gifDecoder.done) {
if (this._decoder.done) {
var frameData = new FrameData {
gifFrame = gifDecoder.currentFrame,
};
Promise<FrameData> frame;
lock (this._frames) {
if (i < this._frames.Count) {
}
else {
D.assert(this._frames.Count == i);
this._frames.Add(new Promise<FrameData>());
}
i++;
frame = this._frames[i];
}
window.runInMain(() => { frame.Resolve(frameData); });
i++;
yield return null;
D.assert(gifDecoder.frameCount == i);
this._frameCount = gifDecoder.frameCount;
this._repetitionCount = gifDecoder.loopCount;
D.assert(this._decoder.frameCount == i);
this._frameCount = this._decoder.frameCount;
this._repetitionCount = this._decoder.loopCount;
this._isDone = true;
}

void _nextFrame() {
this._frameIndex++;
this._coroutine.MoveNext();
this._isDone = false;
this._coroutine = this._startDecoding();
this._coroutine.MoveNext();
public IPromise<FrameInfo> getNextFrame() {
Promise<FrameData> frame;
lock (this._frames) {
if (this._frameIndex == this._frames.Count) {
this._frames.Add(new Promise<FrameData>());
}
else {
D.assert(this._frameIndex < this._frames.Count);
}
frame = this._frames[this._frameIndex];
}
return frame.Then(frameData => {
this._nextFrame();
if (this._texture == null) {
this._texture = new Texture2D(this._width, this._height, TextureFormat.BGRA32, false);
this._texture.hideFlags = HideFlags.HideAndDontSave;
}
var tex = this._texture;
tex.LoadRawTextureData(frameData.gifFrame.bytes);
tex.Apply();
if (frameData.frameInfo != null) {
return frameData.frameInfo;
}
frameData.frameInfo = new FrameInfo {
image = new Image(tex),
duration = TimeSpan.FromMilliseconds(frameData.gifFrame.delay)
};
// frameData.gifFrame = null; // dispose gifFrame
return frameData.frameInfo;
});
public FrameInfo getNextFrame() {
this._nextFrame();
this._texture.LoadRawTextureData(this._frameData.gifFrame.bytes);
this._texture.Apply();
this._frameData.frameInfo.duration = TimeSpan.FromMilliseconds(this._frameData.gifFrame.delay);
return this._frameData.frameInfo;
this._coroutine.stop();
this._decoder.Dispose();
}
}
}
正在加载...
取消
保存