(WebPDecoder): use IBinaryStream instead of BinaryReader.

This commit is contained in:
morkt 2016-12-03 19:17:30 +04:00
parent e2ec6423d1
commit 0b12c7bcef
3 changed files with 25 additions and 53 deletions

View File

@ -44,9 +44,9 @@ using GameRes.Utility;
namespace GameRes.Formats.Google namespace GameRes.Formats.Google
{ {
internal sealed class WebPDecoder : IDisposable internal sealed class WebPDecoder
{ {
BinaryReader m_input; IBinaryStream m_input;
byte[] m_output; byte[] m_output;
byte[] m_alpha_data; // compressed alpha data (if present) byte[] m_alpha_data; // compressed alpha data (if present)
byte[] m_alpha_plane; // output. Persistent, contains the whole data. byte[] m_alpha_plane; // output. Persistent, contains the whole data.
@ -60,16 +60,16 @@ namespace GameRes.Formats.Google
public byte[] Cache { get { return m_cache; } } public byte[] Cache { get { return m_cache; } }
public byte[] AlphaPlane { get { return m_alpha_plane; } } public byte[] AlphaPlane { get { return m_alpha_plane; } }
public WebPDecoder (Stream input, WebPMetaData info) public WebPDecoder (IBinaryStream input, WebPMetaData info)
{ {
m_input = new ArcView.Reader (input); m_input = input;
m_info = info; m_info = info;
m_stride = (int)info.Width * 4; m_stride = (int)info.Width * 4;
m_output = new byte[m_stride * (int)info.Height]; m_output = new byte[m_stride * (int)info.Height];
m_io = new VP8Io(); m_io = new VP8Io();
if (0 != m_info.AlphaOffset) if (0 != m_info.AlphaOffset)
{ {
m_input.BaseStream.Position = m_info.AlphaOffset; m_input.Position = m_info.AlphaOffset;
m_alpha_data = m_input.ReadBytes (m_info.AlphaSize); m_alpha_data = m_input.ReadBytes (m_info.AlphaSize);
m_alpha_plane = new byte[info.Width * info.Height]; m_alpha_plane = new byte[info.Width * info.Height];
Format = PixelFormats.Bgra32; Format = PixelFormats.Bgra32;
@ -94,7 +94,7 @@ namespace GameRes.Formats.Google
public void Decode () public void Decode ()
{ {
m_input.BaseStream.Position = m_info.DataOffset; m_input.Position = m_info.DataOffset;
if (m_info.IsLossless) if (m_info.IsLossless)
{ {
m_io.opaque = m_output; m_io.opaque = m_output;
@ -112,14 +112,6 @@ namespace GameRes.Formats.Google
} }
} }
int ReadInt24 ()
{
int v = m_input.ReadByte();
v |= m_input.ReadByte() << 8;
v |= m_input.ReadByte() << 16;
return v;
}
internal class FrameHeader internal class FrameHeader
{ {
public bool KeyFrame; public bool KeyFrame;
@ -230,7 +222,7 @@ namespace GameRes.Formats.Google
{ {
int chunk_size = m_info.DataSize; int chunk_size = m_info.DataSize;
int bits = ReadInt24(); int bits = m_input.ReadInt24();
chunk_size -= 3; chunk_size -= 3;
m_frame_header.KeyFrame = 0 == (bits & 1); m_frame_header.KeyFrame = 0 == (bits & 1);
m_frame_header.Profile = (bits >> 1) & 7; m_frame_header.Profile = (bits >> 1) & 7;
@ -372,26 +364,26 @@ namespace GameRes.Formats.Google
bool ParsePartitions (BitReader br, int size) bool ParsePartitions (BitReader br, int size)
{ {
long part_end = m_input.BaseStream.Position + size; long part_end = m_input.Position + size;
int size_left = size; int size_left = size;
m_num_parts = 1 << br.GetBits (2); m_num_parts = 1 << br.GetBits (2);
int last_part = m_num_parts - 1; int last_part = m_num_parts - 1;
if (size < 3 * last_part) if (size < 3 * last_part)
return false; return false;
long part_start = m_input.BaseStream.Position + last_part * 3; long part_start = m_input.Position + last_part * 3;
size_left -= last_part * 3; size_left -= last_part * 3;
for (int p = 0; p < last_part; ++p) for (int p = 0; p < last_part; ++p)
{ {
int psize = ReadInt24(); int psize = m_input.ReadInt24();
var sz_pos = m_input.BaseStream.Position; var sz_pos = m_input.Position;
if (psize > size_left) psize = size_left; if (psize > size_left) psize = size_left;
m_input.BaseStream.Position = part_start; m_input.Position = part_start;
m_parts[p] = new BitReader (m_input, psize); m_parts[p] = new BitReader (m_input, psize);
part_start += psize; part_start += psize;
size_left -= psize; size_left -= psize;
m_input.BaseStream.Position = sz_pos; m_input.Position = sz_pos;
} }
m_input.BaseStream.Position = part_start; m_input.Position = part_start;
m_parts[last_part] = new BitReader (m_input, size_left); m_parts[last_part] = new BitReader (m_input, size_left);
return part_start < part_end; return part_start < part_end;
} }
@ -2063,12 +2055,12 @@ namespace GameRes.Formats.Google
public bool Eof { get { return m_eof; } } public bool Eof { get { return m_eof; } }
public BitReader (BinaryReader input, int length) public BitReader (IBinaryStream input, int length)
{ {
Init (input, length); Init (input, length);
} }
public void Init (BinaryReader input, int length) public void Init (IBinaryStream input, int length)
{ {
if (null == m_buf || m_buf.Length < length) if (null == m_buf || m_buf.Length < length)
m_buf = new byte[length]; m_buf = new byte[length];
@ -2285,19 +2277,6 @@ namespace GameRes.Formats.Google
return ok; return ok;
} }
#region IDisposable Members
bool _disposed = false;
public void Dispose ()
{
if (!_disposed)
{
m_input.Dispose();
_disposed = true;
}
GC.SuppressFinalize (this);
}
#endregion
static readonly byte[,,,] CoeffsProba0 = new byte[,,,] { static readonly byte[,,,] CoeffsProba0 = new byte[,,,] {
{ { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, { { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },

View File

@ -86,8 +86,8 @@ namespace GameRes.Formats.Google
if (chunk_size != stream.Read (header, 0, chunk_size)) if (chunk_size != stream.Read (header, 0, chunk_size))
return null; return null;
info.Flags = (WebPFeature)LittleEndian.ToUInt32 (header, 0); info.Flags = (WebPFeature)LittleEndian.ToUInt32 (header, 0);
info.Width = 1 + GetUInt24 (header, 4); info.Width = 1 + (uint)header.ToInt24 (4);
info.Height = 1 + GetUInt24 (header, 7); info.Height = 1 + (uint)header.ToInt24 (7);
if ((long)info.Width * info.Height >= (1L << 32)) if ((long)info.Width * info.Height >= (1L << 32))
return null; return null;
continue; continue;
@ -96,7 +96,7 @@ namespace GameRes.Formats.Google
{ {
info.IsLossless = header[3] == 'L'; info.IsLossless = header[3] == 'L';
info.DataOffset = stream.Position; info.DataOffset = stream.Position;
info.DataSize = chunk_size; info.DataSize = aligned_size;
if (!found_vp8x) if (!found_vp8x)
{ {
if (chunk_size < 10 || 10 != stream.Read (header, 0, 10)) if (chunk_size < 10 || 10 != stream.Read (header, 0, 10))
@ -134,18 +134,11 @@ namespace GameRes.Formats.Google
return info; return info;
} }
static uint GetUInt24 (byte[] src, int offset)
{
return (uint)(src[offset] | src[offset+1] << 8 | src[offset+2] << 16);
}
public override ImageData Read (IBinaryStream stream, ImageMetaData info) public override ImageData Read (IBinaryStream stream, ImageMetaData info)
{ {
using (var reader = new WebPDecoder (stream.AsStream, (WebPMetaData)info)) var reader = new WebPDecoder (stream, (WebPMetaData)info);
{ reader.Decode();
reader.Decode(); return ImageData.Create (info, reader.Format, null, reader.Output);
return ImageData.Create (info, reader.Format, null, reader.Output);
}
} }
public override void Write (Stream file, ImageData image) public override void Write (Stream file, ImageData image)

View File

@ -599,7 +599,7 @@ namespace GameRes.Formats.Google
br_.Init (data, data_i, (uint)data_size); br_.Init (data, data_i, (uint)data_size);
} }
public void Init (BinaryReader input, int length, VP8Io io) public void Init (IBinaryStream input, int length, VP8Io io)
{ {
io_ = io; io_ = io;
br_.Init (input, (uint)length); br_.Init (input, (uint)length);
@ -1614,7 +1614,7 @@ namespace GameRes.Formats.Google
{ {
ulong val_; // pre-fetched bits ulong val_; // pre-fetched bits
byte[] buf_; // input byte buffer byte[] buf_; // input byte buffer
uint end_pos_; // buffer length uint end_pos_; // buffer length
uint pos_; // byte position in buf_ uint pos_; // byte position in buf_
int bit_pos_; // current bit-reading position in val_ int bit_pos_; // current bit-reading position in val_
bool eos_; // true if a bit was read past the end of buffer bool eos_; // true if a bit was read past the end of buffer
@ -1653,7 +1653,7 @@ namespace GameRes.Formats.Google
buf_ = input; buf_ = input;
} }
public void Init (BinaryReader input, uint length) public void Init (IBinaryStream input, uint length)
{ {
var buf = input.ReadBytes ((int)length); var buf = input.ReadBytes ((int)length);
if (buf.Length != length) if (buf.Length != length)