Updated VideoPlayerWidget to play new IVideo data
Added optional padding to video frames because that's what VideoPlayerWidget expects. Keeping the option to not use padding for other use-cases like converting frames to PNG.
This commit is contained in:
committed by
Matthias Mailänder
parent
ee29d0f9c7
commit
c4ab7041b8
@@ -15,15 +15,15 @@ namespace OpenRA.Video
|
|||||||
{
|
{
|
||||||
public interface IVideoLoader
|
public interface IVideoLoader
|
||||||
{
|
{
|
||||||
bool TryParseVideo(Stream s, out IVideo video);
|
bool TryParseVideo(Stream s, bool useFramePadding, out IVideo video);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class VideoLoader
|
public static class VideoLoader
|
||||||
{
|
{
|
||||||
public static IVideo GetVideo(Stream stream, IVideoLoader[] loaders)
|
public static IVideo GetVideo(Stream stream, bool useFramePadding, IVideoLoader[] loaders)
|
||||||
{
|
{
|
||||||
foreach (var loader in loaders)
|
foreach (var loader in loaders)
|
||||||
if (loader.TryParseVideo(stream, out var video))
|
if (loader.TryParseVideo(stream, useFramePadding, out var video))
|
||||||
return video;
|
return video;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
readonly uint[] offsets;
|
readonly uint[] offsets;
|
||||||
readonly uint[] palette;
|
readonly uint[] palette;
|
||||||
readonly uint videoFlags; // if 0x10 is set the video is a 16 bit hq video (ts and later)
|
readonly uint videoFlags; // if 0x10 is set the video is a 16 bit hq video (ts and later)
|
||||||
|
readonly ushort totalFrameWidth;
|
||||||
|
|
||||||
// Stores a list of subpixels, referenced by the VPTZ chunk
|
// Stores a list of subpixels, referenced by the VPTZ chunk
|
||||||
byte[] cbf;
|
byte[] cbf;
|
||||||
@@ -60,7 +61,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
// Top half contains block info, bottom half contains references to cbf array
|
// Top half contains block info, bottom half contains references to cbf array
|
||||||
byte[] origData;
|
byte[] origData;
|
||||||
|
|
||||||
public VqaReader(Stream stream)
|
public VqaReader(Stream stream, bool useFramePadding)
|
||||||
{
|
{
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
|
|
||||||
@@ -145,7 +146,17 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
|
|
||||||
CollectAudioData();
|
CollectAudioData();
|
||||||
|
|
||||||
CurrentFrameData = new byte[Width * Height * 4];
|
if (useFramePadding)
|
||||||
|
{
|
||||||
|
var frameSize = Exts.NextPowerOf2(Math.Max(Width, Height));
|
||||||
|
CurrentFrameData = new byte[frameSize * frameSize * 4];
|
||||||
|
totalFrameWidth = (ushort)frameSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentFrameData = new byte[Width * Height * 4];
|
||||||
|
totalFrameWidth = Width;
|
||||||
|
}
|
||||||
|
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
@@ -485,7 +496,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
|
|
||||||
var pixelX = x * blockWidth + i;
|
var pixelX = x * blockWidth + i;
|
||||||
var pixelY = y * blockHeight + j;
|
var pixelY = y * blockHeight + j;
|
||||||
var pos = pixelY * Width + pixelX;
|
var pos = pixelY * totalFrameWidth + pixelX;
|
||||||
CurrentFrameData[pos * 4] = (byte)(color & 0xFF);
|
CurrentFrameData[pos * 4] = (byte)(color & 0xFF);
|
||||||
CurrentFrameData[pos * 4 + 1] = (byte)(color >> 8 & 0xFF);
|
CurrentFrameData[pos * 4 + 1] = (byte)(color >> 8 & 0xFF);
|
||||||
CurrentFrameData[pos * 4 + 2] = (byte)(color >> 16 & 0xFF);
|
CurrentFrameData[pos * 4 + 2] = (byte)(color >> 16 & 0xFF);
|
||||||
@@ -511,7 +522,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
|
|
||||||
var pixelX = x * blockWidth + bx;
|
var pixelX = x * blockWidth + bx;
|
||||||
var pixelY = y * blockHeight + by;
|
var pixelY = y * blockHeight + by;
|
||||||
var pos = pixelY * Width + pixelX;
|
var pos = pixelY * totalFrameWidth + pixelX;
|
||||||
CurrentFrameData[pos * 4] = cbf[offset + p + 2];
|
CurrentFrameData[pos * 4] = cbf[offset + p + 2];
|
||||||
CurrentFrameData[pos * 4 + 1] = cbf[offset + p + 1];
|
CurrentFrameData[pos * 4 + 1] = cbf[offset + p + 1];
|
||||||
CurrentFrameData[pos * 4 + 2] = cbf[offset + p];
|
CurrentFrameData[pos * 4 + 2] = cbf[offset + p];
|
||||||
|
|||||||
@@ -34,11 +34,12 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
readonly Stream stream;
|
readonly Stream stream;
|
||||||
readonly uint[] palette;
|
readonly uint[] palette;
|
||||||
readonly uint[] frameOffsets;
|
readonly uint[] frameOffsets;
|
||||||
|
readonly ushort totalFrameWidth;
|
||||||
|
|
||||||
byte[] previousFramePaletteIndexData;
|
byte[] previousFramePaletteIndexData;
|
||||||
byte[] currentFramePaletteIndexData;
|
byte[] currentFramePaletteIndexData;
|
||||||
|
|
||||||
public WsaReader(Stream stream)
|
public WsaReader(Stream stream, bool useFramePadding)
|
||||||
{
|
{
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
|
|
||||||
@@ -78,7 +79,17 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
frameOffsets[i] += 768;
|
frameOffsets[i] += 768;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentFrameData = new byte[Width * Height * 4];
|
if (useFramePadding)
|
||||||
|
{
|
||||||
|
var frameSize = Exts.NextPowerOf2(Math.Max(Width, Height));
|
||||||
|
CurrentFrameData = new byte[frameSize * frameSize * 4];
|
||||||
|
totalFrameWidth = (ushort)frameSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentFrameData = new byte[Width * Height * 4];
|
||||||
|
totalFrameWidth = Width;
|
||||||
|
}
|
||||||
|
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
@@ -133,6 +144,9 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
CurrentFrameData[position++] = (byte)(color >> 16 & 0xFF);
|
CurrentFrameData[position++] = (byte)(color >> 16 & 0xFF);
|
||||||
CurrentFrameData[position++] = (byte)(color >> 24 & 0xFF);
|
CurrentFrameData[position++] = (byte)(color >> 24 & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recalculate the position in the byte array to the start of the next pixel row just in case there is padding in the frame.
|
||||||
|
position = (y + 1) * totalFrameWidth * 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ namespace OpenRA.Mods.Cnc.VideoLoaders
|
|||||||
{
|
{
|
||||||
public class VqaLoader : IVideoLoader
|
public class VqaLoader : IVideoLoader
|
||||||
{
|
{
|
||||||
public bool TryParseVideo(Stream s, out IVideo video)
|
public bool TryParseVideo(Stream s, bool useFramePadding, out IVideo video)
|
||||||
{
|
{
|
||||||
video = null;
|
video = null;
|
||||||
|
|
||||||
if (!IsWestwoodVqa(s))
|
if (!IsWestwoodVqa(s))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
video = new VqaReader(s);
|
video = new VqaReader(s, useFramePadding);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ namespace OpenRA.Mods.Cnc.VideoLoaders
|
|||||||
{
|
{
|
||||||
public class WsaLoader : IVideoLoader
|
public class WsaLoader : IVideoLoader
|
||||||
{
|
{
|
||||||
public bool TryParseVideo(Stream s, out IVideo video)
|
public bool TryParseVideo(Stream s, bool useFramePadding, out IVideo video)
|
||||||
{
|
{
|
||||||
video = null;
|
video = null;
|
||||||
|
|
||||||
if (!IsWsa(s))
|
if (!IsWsa(s))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
video = new WsaReader(s);
|
video = new WsaReader(s, useFramePadding);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
|
|
||||||
public static IVideo LoadVideo(Stream s)
|
public static IVideo LoadVideo(Stream s)
|
||||||
{
|
{
|
||||||
return VideoLoader.GetVideo(s, Game.ModData.VideoLoaders);
|
return VideoLoader.GetVideo(s, true, Game.ModData.VideoLoaders);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -506,7 +506,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
// Mute music so it doesn't interfere with the current asset.
|
// Mute music so it doesn't interfere with the current asset.
|
||||||
MuteSounds();
|
MuteSounds();
|
||||||
|
|
||||||
var video = VideoLoader.GetVideo(Game.ModData.DefaultFileSystem.Open(filename), Game.ModData.VideoLoaders);
|
var video = VideoLoader.GetVideo(Game.ModData.DefaultFileSystem.Open(filename), true, Game.ModData.VideoLoaders);
|
||||||
if (video != null)
|
if (video != null)
|
||||||
{
|
{
|
||||||
player = panel.Get<VideoPlayerWidget>("PLAYER");
|
player = panel.Get<VideoPlayerWidget>("PLAYER");
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
float overlayScale;
|
float overlayScale;
|
||||||
bool stopped;
|
bool stopped;
|
||||||
bool paused;
|
bool paused;
|
||||||
|
int textureSize;
|
||||||
|
|
||||||
Action onComplete;
|
Action onComplete;
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
if (filename == cachedVideo)
|
if (filename == cachedVideo)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var video = VideoLoader.GetVideo(Game.ModData.DefaultFileSystem.Open(filename), Game.ModData.VideoLoaders);
|
var video = VideoLoader.GetVideo(Game.ModData.DefaultFileSystem.Open(filename), true, Game.ModData.VideoLoaders);
|
||||||
Open(video);
|
Open(video);
|
||||||
|
|
||||||
cachedVideo = filename;
|
cachedVideo = filename;
|
||||||
@@ -63,11 +64,11 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
invLength = video.Framerate * 1f / video.FrameCount;
|
invLength = video.Framerate * 1f / video.FrameCount;
|
||||||
|
|
||||||
var size = Math.Max(video.Width, video.Height);
|
var size = Math.Max(video.Width, video.Height);
|
||||||
var textureSize = Exts.NextPowerOf2(size);
|
textureSize = Exts.NextPowerOf2(size);
|
||||||
var videoSheet = new Sheet(SheetType.BGRA, new Size(textureSize, textureSize));
|
var videoSheet = new Sheet(SheetType.BGRA, new Size(textureSize, textureSize));
|
||||||
|
|
||||||
videoSheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
|
videoSheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
|
||||||
videoSheet.GetTexture().SetData(video.CurrentFrameData);
|
videoSheet.GetTexture().SetData(video.CurrentFrameData, textureSize, textureSize);
|
||||||
|
|
||||||
videoSprite = new Sprite(videoSheet,
|
videoSprite = new Sprite(videoSheet,
|
||||||
new Rectangle(
|
new Rectangle(
|
||||||
@@ -110,12 +111,12 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
while (nextFrame > video.CurrentFrameNumber)
|
while (nextFrame > video.CurrentFrameNumber)
|
||||||
{
|
{
|
||||||
video.AdvanceFrame();
|
video.AdvanceFrame();
|
||||||
videoSprite.Sheet.GetTexture().SetData(video.CurrentFrameData);
|
videoSprite.Sheet.GetTexture().SetData(video.CurrentFrameData, textureSize, textureSize);
|
||||||
skippedFrames++;
|
skippedFrames++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skippedFrames > 1)
|
if (skippedFrames > 1)
|
||||||
Log.Write("perf", "VqaPlayer : {0} skipped {1} frames at position {2}", cachedVideo, skippedFrames, video.CurrentFrameNumber);
|
Log.Write("perf", "VideoPlayer: {0} skipped {1} frames at position {2}", cachedVideo, skippedFrames, video.CurrentFrameNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
WidgetUtils.DrawSprite(videoSprite, videoOrigin, videoSize);
|
WidgetUtils.DrawSprite(videoSprite, videoOrigin, videoSize);
|
||||||
@@ -218,7 +219,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
paused = true;
|
paused = true;
|
||||||
Game.Sound.StopVideo();
|
Game.Sound.StopVideo();
|
||||||
video.Reset();
|
video.Reset();
|
||||||
videoSprite.Sheet.GetTexture().SetData(video.CurrentFrameData);
|
videoSprite.Sheet.GetTexture().SetData(video.CurrentFrameData, textureSize, textureSize);
|
||||||
Game.RunAfterTick(onComplete);
|
Game.RunAfterTick(onComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user