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:
penev92
2021-09-22 01:58:33 +03:00
committed by Matthias Mailänder
parent ee29d0f9c7
commit c4ab7041b8
8 changed files with 47 additions and 21 deletions

View File

@@ -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;

View File

@@ -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];

View File

@@ -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;
} }
} }
} }

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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);
} }
} }
} }

View File

@@ -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");

View File

@@ -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);
} }