Addressed review comments
- Renamed `IVideo.CurrentFrameNumber` to `CurrentFrameIndex` - Improved logged error message in VideoPlayerWidget - Renumbered fields in ThreadedGraphicsContext
This commit is contained in:
committed by
Matthias Mailänder
parent
248b8d1102
commit
860ec642b8
@@ -22,7 +22,7 @@ namespace OpenRA.Video
|
|||||||
/// Current frame color data in 32-bit BGRA.
|
/// Current frame color data in 32-bit BGRA.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
byte[] CurrentFrameData { get; }
|
byte[] CurrentFrameData { get; }
|
||||||
int CurrentFrameNumber { get; }
|
int CurrentFrameIndex { get; }
|
||||||
void AdvanceFrame();
|
void AdvanceFrame();
|
||||||
|
|
||||||
bool HasAudio { get; }
|
bool HasAudio { get; }
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
public ushort Height { get; }
|
public ushort Height { get; }
|
||||||
|
|
||||||
public byte[] CurrentFrameData { get; }
|
public byte[] CurrentFrameData { get; }
|
||||||
public int CurrentFrameNumber { get; private set; }
|
public int CurrentFrameIndex { get; private set; }
|
||||||
|
|
||||||
public bool HasAudio { get; set; }
|
public bool HasAudio { get; set; }
|
||||||
public byte[] AudioData { get; private set; } // audio for this frame: 22050Hz 16bit mono pcm, uncompressed.
|
public byte[] AudioData { get; private set; } // audio for this frame: 22050Hz 16bit mono pcm, uncompressed.
|
||||||
@@ -163,7 +163,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
CurrentFrameNumber = chunkBufferOffset = currentChunkBuffer = 0;
|
CurrentFrameIndex = chunkBufferOffset = currentChunkBuffer = 0;
|
||||||
LoadFrame();
|
LoadFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,18 +260,18 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
|
|
||||||
public void AdvanceFrame()
|
public void AdvanceFrame()
|
||||||
{
|
{
|
||||||
CurrentFrameNumber++;
|
CurrentFrameIndex++;
|
||||||
LoadFrame();
|
LoadFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadFrame()
|
void LoadFrame()
|
||||||
{
|
{
|
||||||
if (CurrentFrameNumber >= FrameCount)
|
if (CurrentFrameIndex >= FrameCount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Seek to the start of the frame
|
// Seek to the start of the frame
|
||||||
stream.Seek(offsets[CurrentFrameNumber], SeekOrigin.Begin);
|
stream.Seek(offsets[CurrentFrameIndex], SeekOrigin.Begin);
|
||||||
var end = (CurrentFrameNumber < FrameCount - 1) ? offsets[CurrentFrameNumber + 1] : stream.Length;
|
var end = (CurrentFrameIndex < FrameCount - 1) ? offsets[CurrentFrameIndex + 1] : stream.Length;
|
||||||
|
|
||||||
while (stream.Position < end)
|
while (stream.Position < end)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
public ushort Height { get; }
|
public ushort Height { get; }
|
||||||
|
|
||||||
public byte[] CurrentFrameData { get; }
|
public byte[] CurrentFrameData { get; }
|
||||||
public int CurrentFrameNumber { get; private set; }
|
public int CurrentFrameIndex { get; private set; }
|
||||||
|
|
||||||
public bool HasAudio => false;
|
public bool HasAudio => false;
|
||||||
public byte[] AudioData => null;
|
public byte[] AudioData => null;
|
||||||
@@ -99,7 +99,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
CurrentFrameNumber = 0;
|
CurrentFrameIndex = 0;
|
||||||
previousFramePaletteIndexData = null;
|
previousFramePaletteIndexData = null;
|
||||||
LoadFrame();
|
LoadFrame();
|
||||||
}
|
}
|
||||||
@@ -107,18 +107,18 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
|||||||
public void AdvanceFrame()
|
public void AdvanceFrame()
|
||||||
{
|
{
|
||||||
previousFramePaletteIndexData = currentFramePaletteIndexData;
|
previousFramePaletteIndexData = currentFramePaletteIndexData;
|
||||||
CurrentFrameNumber++;
|
CurrentFrameIndex++;
|
||||||
LoadFrame();
|
LoadFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadFrame()
|
void LoadFrame()
|
||||||
{
|
{
|
||||||
if (CurrentFrameNumber >= FrameCount)
|
if (CurrentFrameIndex >= FrameCount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
stream.Seek(frameOffsets[CurrentFrameNumber], SeekOrigin.Begin);
|
stream.Seek(frameOffsets[CurrentFrameIndex], SeekOrigin.Begin);
|
||||||
|
|
||||||
var dataLength = frameOffsets[CurrentFrameNumber + 1] - frameOffsets[CurrentFrameNumber];
|
var dataLength = frameOffsets[CurrentFrameIndex + 1] - frameOffsets[CurrentFrameIndex];
|
||||||
|
|
||||||
var rawData = StreamExts.ReadBytes(stream, (int)dataLength);
|
var rawData = StreamExts.ReadBytes(stream, (int)dataLength);
|
||||||
var intermediateData = new byte[Width * Height];
|
var intermediateData = new byte[Width * Height];
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
frameSlider.GetValue = () =>
|
frameSlider.GetValue = () =>
|
||||||
{
|
{
|
||||||
if (isVideoLoaded)
|
if (isVideoLoaded)
|
||||||
return player.Video.CurrentFrameNumber;
|
return player.Video.CurrentFrameIndex;
|
||||||
|
|
||||||
if (currentSound != null)
|
if (currentSound != null)
|
||||||
return currentSound.SeekPosition * currentSoundFormat.SampleRate;
|
return currentSound.SeekPosition * currentSoundFormat.SampleRate;
|
||||||
@@ -197,7 +197,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
frameText.GetText = () =>
|
frameText.GetText = () =>
|
||||||
{
|
{
|
||||||
if (isVideoLoaded)
|
if (isVideoLoaded)
|
||||||
return $"{player.Video.CurrentFrameNumber + 1} / {player.Video.FrameCount}";
|
return $"{player.Video.CurrentFrameIndex + 1} / {player.Video.FrameCount}";
|
||||||
|
|
||||||
if (currentSoundFormat != null)
|
if (currentSoundFormat != null)
|
||||||
return $"{Math.Round(currentSoundFormat.LengthInSeconds, 3)} sec";
|
return $"{Math.Round(currentSoundFormat.LengthInSeconds, 3)} sec";
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
Sprite videoSprite, overlaySprite;
|
Sprite videoSprite, overlaySprite;
|
||||||
Sheet overlaySheet;
|
Sheet overlaySheet;
|
||||||
IVideo video = null;
|
IVideo video = null;
|
||||||
string cachedVideo;
|
string cachedVideoFileName;
|
||||||
float invLength;
|
float invLength;
|
||||||
float2 videoOrigin, videoSize;
|
float2 videoOrigin, videoSize;
|
||||||
float2 overlayOrigin, overlaySize;
|
float2 overlayOrigin, overlaySize;
|
||||||
@@ -43,13 +43,13 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
|
|
||||||
public void Load(string filename)
|
public void Load(string filename)
|
||||||
{
|
{
|
||||||
if (filename == cachedVideo)
|
if (filename == cachedVideoFileName)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var video = VideoLoader.GetVideo(Game.ModData.DefaultFileSystem.Open(filename), true, Game.ModData.VideoLoaders);
|
var video = VideoLoader.GetVideo(Game.ModData.DefaultFileSystem.Open(filename), true, Game.ModData.VideoLoaders);
|
||||||
Open(video);
|
Open(video);
|
||||||
|
|
||||||
cachedVideo = filename;
|
cachedVideoFileName = filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Open(IVideo video)
|
public void Open(IVideo video)
|
||||||
@@ -98,17 +98,17 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
if (video.HasAudio && !Game.Sound.DummyEngine)
|
if (video.HasAudio && !Game.Sound.DummyEngine)
|
||||||
nextFrame = (int)float2.Lerp(0, video.FrameCount, Game.Sound.VideoSeekPosition * invLength);
|
nextFrame = (int)float2.Lerp(0, video.FrameCount, Game.Sound.VideoSeekPosition * invLength);
|
||||||
else
|
else
|
||||||
nextFrame = video.CurrentFrameNumber + 1;
|
nextFrame = video.CurrentFrameIndex + 1;
|
||||||
|
|
||||||
// Without the 2nd check the sound playback sometimes ends before the final frame is displayed which causes the player to be stuck on the first frame
|
// Without the 2nd check the sound playback sometimes ends before the final frame is displayed which causes the player to be stuck on the first frame
|
||||||
if (nextFrame > video.FrameCount || nextFrame < video.CurrentFrameNumber)
|
if (nextFrame > video.FrameCount || nextFrame < video.CurrentFrameIndex)
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var skippedFrames = 0;
|
var skippedFrames = 0;
|
||||||
while (nextFrame > video.CurrentFrameNumber)
|
while (nextFrame > video.CurrentFrameIndex)
|
||||||
{
|
{
|
||||||
video.AdvanceFrame();
|
video.AdvanceFrame();
|
||||||
videoSprite.Sheet.GetTexture().SetData(video.CurrentFrameData, textureSize, textureSize);
|
videoSprite.Sheet.GetTexture().SetData(video.CurrentFrameData, textureSize, textureSize);
|
||||||
@@ -116,7 +116,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (skippedFrames > 1)
|
if (skippedFrames > 1)
|
||||||
Log.Write("perf", "VideoPlayer: {0} skipped {1} frames at position {2}", cachedVideo, skippedFrames, video.CurrentFrameNumber);
|
Log.Write("perf", $"{nameof(VideoPlayerWidget)}: {cachedVideoFileName} skipped {skippedFrames} frames at position {video.CurrentFrameIndex}");
|
||||||
}
|
}
|
||||||
|
|
||||||
WidgetUtils.DrawSprite(videoSprite, videoOrigin, videoSize);
|
WidgetUtils.DrawSprite(videoSprite, videoOrigin, videoSize);
|
||||||
|
|||||||
@@ -557,10 +557,10 @@ namespace OpenRA.Platforms.Default
|
|||||||
readonly Func<object> getSize;
|
readonly Func<object> getSize;
|
||||||
readonly Action<object> setEmpty;
|
readonly Action<object> setEmpty;
|
||||||
readonly Func<byte[]> getData;
|
readonly Func<byte[]> getData;
|
||||||
readonly Action<object> setData2;
|
readonly Action<object> setData1;
|
||||||
readonly Func<object, object> setData3;
|
readonly Func<object, object> setData2;
|
||||||
readonly Action<object> setData4;
|
readonly Action<object> setData3;
|
||||||
readonly Func<object, object> setData5;
|
readonly Func<object, object> setData4;
|
||||||
readonly Action dispose;
|
readonly Action dispose;
|
||||||
|
|
||||||
public ThreadedTexture(ThreadedGraphicsContext device, ITextureInternal texture)
|
public ThreadedTexture(ThreadedGraphicsContext device, ITextureInternal texture)
|
||||||
@@ -572,10 +572,10 @@ namespace OpenRA.Platforms.Default
|
|||||||
getSize = () => texture.Size;
|
getSize = () => texture.Size;
|
||||||
setEmpty = tuple => { var t = (ValueTuple<int, int>)tuple; texture.SetEmpty(t.Item1, t.Item2); };
|
setEmpty = tuple => { var t = (ValueTuple<int, int>)tuple; texture.SetEmpty(t.Item1, t.Item2); };
|
||||||
getData = () => texture.GetData();
|
getData = () => texture.GetData();
|
||||||
setData2 = tuple => { var t = (ValueTuple<byte[], int, int>)tuple; texture.SetData(t.Item1, t.Item2, t.Item3); };
|
setData1 = tuple => { var t = (ValueTuple<byte[], int, int>)tuple; texture.SetData(t.Item1, t.Item2, t.Item3); };
|
||||||
setData3 = tuple => { setData2(tuple); return null; };
|
setData2 = tuple => { setData1(tuple); return null; };
|
||||||
setData4 = tuple => { var t = (ValueTuple<float[], int, int>)tuple; texture.SetFloatData(t.Item1, t.Item2, t.Item3); };
|
setData3 = tuple => { var t = (ValueTuple<float[], int, int>)tuple; texture.SetFloatData(t.Item1, t.Item2, t.Item3); };
|
||||||
setData5 = tuple => { setData4(tuple); return null; };
|
setData4 = tuple => { setData3(tuple); return null; };
|
||||||
dispose = texture.Dispose;
|
dispose = texture.Dispose;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,13 +609,13 @@ namespace OpenRA.Platforms.Default
|
|||||||
// If we are able to create a small array the GC can collect easily, post a message to avoid blocking.
|
// If we are able to create a small array the GC can collect easily, post a message to avoid blocking.
|
||||||
var temp = new byte[colors.Length];
|
var temp = new byte[colors.Length];
|
||||||
Array.Copy(colors, temp, temp.Length);
|
Array.Copy(colors, temp, temp.Length);
|
||||||
device.Post(setData2, (temp, width, height));
|
device.Post(setData1, (temp, width, height));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the length is large and would result in an array on the Large Object Heap (LOH),
|
// If the length is large and would result in an array on the Large Object Heap (LOH),
|
||||||
// send a message and block to avoid LOH allocation as this requires a Gen2 collection.
|
// send a message and block to avoid LOH allocation as this requires a Gen2 collection.
|
||||||
device.Send(setData3, (colors, width, height));
|
device.Send(setData2, (colors, width, height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,13 +628,13 @@ namespace OpenRA.Platforms.Default
|
|||||||
// If we are able to create a small array the GC can collect easily, post a message to avoid blocking.
|
// If we are able to create a small array the GC can collect easily, post a message to avoid blocking.
|
||||||
var temp = new float[data.Length];
|
var temp = new float[data.Length];
|
||||||
Array.Copy(data, temp, temp.Length);
|
Array.Copy(data, temp, temp.Length);
|
||||||
device.Post(setData4, (temp, width, height));
|
device.Post(setData3, (temp, width, height));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the length is large and would result in an array on the Large Object Heap (LOH),
|
// If the length is large and would result in an array on the Large Object Heap (LOH),
|
||||||
// send a message and block to avoid LOH allocation as this requires a Gen2 collection.
|
// send a message and block to avoid LOH allocation as this requires a Gen2 collection.
|
||||||
device.Send(setData5, (data, width, height));
|
device.Send(setData4, (data, width, height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user