Skip to content

Commit

Permalink
wip frame export
Browse files Browse the repository at this point in the history
  • Loading branch information
Russ committed Jun 6, 2024
1 parent ca6635e commit 87f91bf
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 17 deletions.
22 changes: 10 additions & 12 deletions Core/Maths/Color/Profile.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using OpenTK.Mathematics;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace Octopus.Player.Core.Maths.Color
{
public struct Profile
public readonly struct Profile
{
public static Vector3 Rec709LuminanceWeights { get { return new Vector3(0.2126f, 0.7152f, 0.0722f); } }

Expand Down Expand Up @@ -56,13 +54,13 @@ public Profile(IO.DNG.Reader reader) : this()
asShotWhiteXY = reader.AsShotWhiteXY;
}

public Tuple<double,double> AsShotWhiteBalance()
public readonly Tuple<double,double> AsShotWhiteBalance()
{
Debug.Assert(asShotWhiteXY.HasValue);
return Temperature.ChromaticityToTemperatureTint(asShotWhiteXY.Value);
}

public Matrix3 XYZToCamera(in Vector2 whiteXY)
public readonly Matrix3 XYZToCamera(in Vector2 whiteXY)
{
if (!isDualIlluminant)
return colorMatrix1;
Expand Down Expand Up @@ -93,7 +91,7 @@ public Matrix3 XYZToCamera(in Vector2 whiteXY)
return Matrix.InterpolateColourMatrix(colorMatrix2, colorMatrix1, (float)g);
}

public Vector2 NeutralToXY(in Vector3 neutral)
public readonly Vector2 NeutralToXY(in Vector3 neutral)
{
const uint kMaxPasses = 30;

Expand Down Expand Up @@ -127,7 +125,7 @@ public Vector2 NeutralToXY(in Vector3 neutral)
return last;
}

public Matrix3 CameraToXYZ(uint colorTemperature)
public readonly Matrix3 CameraToXYZ(uint colorTemperature)
{
Debug.Assert(hasForwardMatrix, "Warning, using CameraToXYZ for colour profile without Forward Matrices, please use XYZToCamera");

Expand Down Expand Up @@ -179,19 +177,19 @@ public Matrix3 CameraToXYZ(uint colorTemperature)
}
}

public Matrix3 CalculateCameraToXYZD50(Tuple<float,float> whiteBalance)
public readonly Matrix3 CalculateCameraToXYZD50(Tuple<float,float> whiteBalance)
{
return (whiteBalance != null) ? CalculateCameraToXYZD50(Temperature.ColourTemperatureToChromaticity(whiteBalance.Item1, whiteBalance.Item2)) :
CalculateCameraToXYZD50();
}

public Matrix3 CalculateCameraToXYZD65(Tuple<float, float> whiteBalance)
public readonly Matrix3 CalculateCameraToXYZD65(Tuple<float, float> whiteBalance)
{
return (whiteBalance != null) ? CalculateCameraToXYZD65(Temperature.ColourTemperatureToChromaticity(whiteBalance.Item1, whiteBalance.Item2)) :
CalculateCameraToXYZD65();
}

public Matrix3 CalculateCameraToXYZD50(Vector2? whiteXY = null)
public readonly Matrix3 CalculateCameraToXYZD50(Vector2? whiteXY = null)
{
Debug.Assert(whiteXY != null || asShotWhiteXY.HasValue);
if (!whiteXY.HasValue)
Expand Down Expand Up @@ -230,7 +228,7 @@ public Matrix3 CalculateCameraToXYZD50(Vector2? whiteXY = null)
}
}

public Matrix3 CalculateCameraToXYZD65(Vector2? whiteXY = null)
public readonly Matrix3 CalculateCameraToXYZD65(Vector2? whiteXY = null)
{
Debug.Assert(asShotWhiteXY.HasValue);
if (!whiteXY.HasValue)
Expand Down Expand Up @@ -267,7 +265,7 @@ public Matrix3 CalculateCameraToXYZD65(Vector2? whiteXY = null)
}
}

public override string ToString()
public readonly override string ToString()
{
string text = "";
text += "\nAs Shot XY: " + (asShotWhiteXY.HasValue ? asShotWhiteXY.Value.ToString() : "Unknown");
Expand Down
14 changes: 13 additions & 1 deletion Core/Playback/IPlayback.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using OpenTK.Mathematics;

namespace Octopus.Player.Core.Playback
{
Expand Down Expand Up @@ -35,6 +36,14 @@ public static bool IsForward(this PlaybackVelocity velocity)
}
}

public readonly struct ExportedFrame
{
public readonly byte[] data;
public readonly Vector2i dimensions;
public readonly GPU.Format format;
public readonly uint frameNumber;
}

public interface IPlayback : IDisposable
{
uint FirstFrame { get; }
Expand Down Expand Up @@ -86,7 +95,10 @@ public interface IPlayback : IDisposable
event EventHandler ClipOpened;
event EventHandler ClipClosed;

void OnRenderFrame(double timeInterval);
// Export
Error ExportFrame(out ExportedFrame frame, uint? frameNumber = null);

void OnRenderFrame(double timeInterval);
}
}

1 change: 1 addition & 0 deletions Core/Playback/Playback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,5 +347,6 @@ public virtual void Dispose()
public abstract Error ApplyLUT(string resourceName);
public abstract Error ApplyLUT(Uri path);
public abstract void RemoveLUT();
public abstract Error ExportFrame(out ExportedFrame frame, uint? frameNumber = null);
}
}
22 changes: 22 additions & 0 deletions Core/Playback/PlaybackCinemaDNG.cs
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,28 @@ public override Error ApplyLUT(Uri path)
return Error.InvalidLutFile;
}
}

public override Error ExportFrame(out ExportedFrame frame, uint? frameNumber = null)
{
frame = new ExportedFrame();

using var frameIn = new SequenceFrameDNG(ComputeContext, ComputeContext.DefaultQueue, Clip, SequenceStream.Format);
using var frameOut = ComputeContext.CreateImage(displayFrameCompute.Dimensions, displayFrameCompute.Format, MemoryDeviceAccess.WriteOnly, MemoryHostAccess.ReadOnly);

frameIn.frameNumber = frameNumber.GetValueOrDefault(LastDisplayedFrame.GetValueOrDefault());

var decodeResult = frameIn.Decode(Clip);
if (decodeResult != Error.None)
return decodeResult;

var processResult = frameIn.Process(Clip, RenderContext, frameOut, LinearizeTable, GpuPipelineComputeProgram, ComputeContext.DefaultQueue, LUT, true);
if (processResult != Error.None)
return processResult;

var data = ComputeContext.DefaultQueue.ReadImage(frameOut);

return Error.None;
}
}
}

6 changes: 3 additions & 3 deletions Core/Playback/Sequence/SequenceFrameDNG.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ private void ForEachTile(IO.DNG.MetadataCinemaDNG metadata, Action<Vector2i, Vec
}

public override Error Process(IClip clip, IContext renderContext, GPU.Compute.IImage2D output, GPU.Compute.IImage1D linearizeTable, GPU.Compute.IProgram program,
GPU.Compute.IQueue queue, IO.LUT.ILUT3D logToDisplay, bool immediate = false, Action postCopyAction = null)
GPU.Compute.IQueue queue, IO.LUT.ILUT3D logToDisplay, bool immediate = false, Action postProcessAction = null)
{
Debug.Assert(clip.GetType() == typeof(ClipCinemaDNG));
var metadata = (IO.DNG.MetadataCinemaDNG)clip.Metadata;
Expand Down Expand Up @@ -218,8 +218,8 @@ private void ForEachTile(IO.DNG.MetadataCinemaDNG metadata, Action<Vector2i, Vec
// Release access to GL texture
queue.ReleaseTextureObject(output);
if (postCopyAction != null)
postCopyAction();
if (postProcessAction != null)
postProcessAction();
};

if (immediate)
Expand Down
1 change: 1 addition & 0 deletions GPU/Common/Compute/IQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public interface IQueue : IDisposable
string Name { get; }

void ModifyImage(IImage2D image, Vector2i origin, Vector2i size, byte[] imageData, uint imageDataOffset = 0);
byte[] ReadImage(IImage2D image);
void Memset(IImage2D image, in Vector4 color);

void AcquireTextureObject(GPU.Render.IContext renderContext, IImage image);
Expand Down
26 changes: 25 additions & 1 deletion GPU/OpenCL/Compute/Queue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using OpenTK.Mathematics;
using Silk.NET.OpenCL;
using System;
using System.Drawing;

namespace Octopus.Player.GPU.OpenCL.Compute
{
Expand Down Expand Up @@ -54,7 +55,6 @@ public void ModifyImage(IImage2D image, Vector2i origin, Vector2i size, byte[] i
var originArray = new nuint[] { (nuint)origin.X, (nuint)origin.Y, 0};
var sizeArray = new nuint[] { (nuint)size.X, (nuint)size.Y, 1 };

nuint stride = (nuint)image.Dimensions.X * (nuint)image.Format.BytesPerPixel();
unsafe
{
fixed (nuint* pOrigin = originArray, pSize = sizeArray)
Expand All @@ -67,6 +67,30 @@ public void ModifyImage(IImage2D image, Vector2i origin, Vector2i size, byte[] i
}
}

public byte[] ReadImage(IImage2D image)
{
var imageCL = (Image2D)image;
if (imageCL == null)
throw new ArgumentException("Invalid image object");

var imageData = new byte[image.Format.BytesPerPixel() * image.Dimensions.Area()];
var originArray = new nuint[] { 0, 0, 0 };
var sizeArray = new nuint[] { (nuint)image.Dimensions.X, (nuint)image.Dimensions.Y, 1 };

unsafe
{
fixed (nuint* pOrigin = originArray, pSize = sizeArray)
{
fixed (byte* pImageData = imageData)
{
Debug.CheckError(Context.Handle.EnqueueReadImage(NativeHandle, imageCL.NativeHandle, true, pOrigin, pSize, 0, 0, pImageData, 0, null, null));
}
}
}

return imageData;
}

public void Memset(IImage2D image, in Vector4 color)
{
var imageCL = (Image2D)image;
Expand Down
1 change: 1 addition & 0 deletions UI/Common/Window/PlayerWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@ public void MenuItemClick(string id)
var pngExtension = new Tuple<string, string>("*.png", "PNG image");
string savePath = NativeWindow.SaveFileDialogue("Export frame as PNG", Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
new List<Tuple<string, string>>() { pngExtension });
//Notification("Frame exported", "Saved to: '" + savePath + "'");
break;

// Clip
Expand Down
2 changes: 2 additions & 0 deletions UI/macOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,7 @@
<string></string>
</dict>
</array>
<key>NSUserNotificationAlertStyle</key>
<string>alert</string>
</dict>
</plist>
14 changes: 14 additions & 0 deletions UI/macOS/NativePlayerWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,20 @@ public void AnimateOutControls()
((NSView)PlaybackControls.Animator).AlphaValue = 0.0f;
});
}

public void Notification(string title, string caption)
{
// Trigger a local notification after the time has elapsed
var notification = new NSUserNotification();

// Add text and sound to the notification
notification.Title = title;
notification.InformativeText = caption;
notification.SoundName = NSUserNotification.NSUserNotificationDefaultSoundName;
notification.HasActionButton = true;

NSUserNotificationCenter.DefaultUserNotificationCenter.DeliverNotification(notification);
}
}
}

0 comments on commit 87f91bf

Please sign in to comment.