Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Moments Recorder/Scripts/Editor/RecorderEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public sealed class RecorderEditor : Editor
SerializedProperty m_Width;
SerializedProperty m_Height;
SerializedProperty m_FramePerSecond;
SerializedProperty m_FramesPerColorSample;
SerializedProperty m_Repeat;
SerializedProperty m_Quality;
SerializedProperty m_BufferSize;
Expand All @@ -45,6 +46,7 @@ void OnEnable()
m_Width = serializedObject.FindProperty("m_Width");
m_Height = serializedObject.FindProperty("m_Height");
m_FramePerSecond = serializedObject.FindProperty("m_FramePerSecond");
m_FramesPerColorSample = serializedObject.FindProperty("m_FramesPerColorSample");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recorder doesn't have a serialized m_FramesPerColorSample field. Did you miss a file in your commit?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're quite right! I hadn't copied my changes to Recorder.cs across. It should be good to go now. Thanks, @Chman.

m_Repeat = serializedObject.FindProperty("m_Repeat");
m_Quality = serializedObject.FindProperty("m_Quality");
m_BufferSize = serializedObject.FindProperty("m_BufferSize");
Expand Down Expand Up @@ -76,6 +78,7 @@ public override void OnInspectorGUI()
EditorGUILayout.PropertyField(m_Quality, new GUIContent("Compression Quality", "Lower values mean better quality but slightly longer processing time. 15 is generally a good middleground value."));
EditorGUILayout.PropertyField(m_Repeat, new GUIContent("Repeat", "-1 to disable, 0 to loop indefinitely, >0 to loop a set number of time."));
EditorGUILayout.PropertyField(m_FramePerSecond, new GUIContent("Frames Per Second", "The number of frames per second the gif will run at."));
EditorGUILayout.PropertyField(m_FramesPerColorSample, new GUIContent("Frames Per Color Sample", "Create the gif's color palette by analysing every n-th frame. Lower values mean better color representation, but much longer processing time. Higher values process faster, but may miss important colors between samples. Zero means a new color palette is created per frame."));
EditorGUILayout.PropertyField(m_BufferSize, new GUIContent("Record Time", "The amount of time (in seconds) to record to memory."));

serializedObject.ApplyModifiedProperties();
Expand Down
66 changes: 63 additions & 3 deletions Moments Recorder/Scripts/Gif/GifEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
*
* Original code by Kevin Weiner, FM Software.
* Adapted by Thomas Hourdel.
* Extended slightly by Paul Kopetko
*/

using System;
using System.IO;
using System.Collections.Generic;
using UnityEngine;

namespace Moments.Encoder
Expand All @@ -33,6 +35,9 @@ public class GifEncoder
protected bool m_IsFirstFrame = true;
protected bool m_IsSizeSet = false; // If false, get size from first frame
protected int m_SampleInterval = 10; // Default sample interval for quantizer
protected int m_FramesPerColorSample = 6; // Default sample rate (in frames per sample) of color palette

protected NeuQuant nq;

/// <summary>
/// Default constructor. Repeat will be set to -1 and Quality to 10.
Expand Down Expand Up @@ -77,6 +82,55 @@ public void SetFrameRate(float fps)
m_FrameDelay = Mathf.RoundToInt(100f / fps);
}

/// <summary>
/// Sets color palette sample rate in frames per sample.
/// </summary>
/// <param name="fps">Frame rate</param>
public void SetFramesPerColorSample(int frames)
{
m_FramesPerColorSample = frames;
}

/// <summary>
/// Builds a colour map out of the combined colours from several frames.
/// </summary>
/// <param name="frames">List of frames to sample colour palette from</param>
public void BuildPalette(ref List<GifFrame> frames)
{

// Do not build the color palette here if user wants separate palettes created per frame
if (m_FramesPerColorSample == 0)
{
return;
}

// Initialize a large image
Byte[] combinedPixels = new Byte[3 * frames[0].Width * frames[0].Height * (1 + frames.Count / m_FramesPerColorSample)];

int count = 0;

// Stich the large image together out of pixels from several frames
for (int i = 0; i < frames.Count; i += m_FramesPerColorSample)
{
Color32[] p = frames[i].Data;
// Texture data is layered down-top, so flip it
for (int th = frames[i].Height - 1; th >= 0; th--)
{
for (int tw = 0; tw < frames[i].Width; tw++)
{
Color32 color = p[th * frames[i].Width + tw];
combinedPixels[count] = color.r; count++;
combinedPixels[count] = color.g; count++;
combinedPixels[count] = color.b; count++;
}
}
}

// Run the quantizer over our stitched together image and create reduced palette
nq = new NeuQuant(combinedPixels, combinedPixels.Length, (int)m_SampleInterval);
m_ColorTab = nq.Process();
}

/// <summary>
/// Adds next GIF frame. The frame is not written immediately, but is actually deferred
/// until the next frame is received so that timing data can be inserted. Invoking
Expand Down Expand Up @@ -222,14 +276,20 @@ protected void GetImagePixels()
}
}

// Analyzes image colors and creates color map.
// Maps image colors to the color map
protected void AnalyzePixels()
{

int len = m_Pixels.Length;
int nPix = len / 3;
m_IndexedPixels = new byte[nPix];
NeuQuant nq = new NeuQuant(m_Pixels, len, (int)m_SampleInterval);
m_ColorTab = nq.Process(); // Create reduced palette

// Analyze image colors and create color map (original, expensive, Moments Recorder behaviour)
if (m_FramesPerColorSample == 0)
{
nq = new NeuQuant(m_Pixels, len, (int)m_SampleInterval);
m_ColorTab = nq.Process(); // Create reduced palette
}

// Map image pixels to new palette
int k = 0;
Expand Down
9 changes: 8 additions & 1 deletion Moments Recorder/Scripts/Recorder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ public sealed class Recorder : MonoBehaviour
[SerializeField, Min(0.1f)]
float m_BufferSize = 3f;

[SerializeField, Range(0, 60)]
int m_FramesPerColorSample = 6;

#endregion

#region Public fields
Expand Down Expand Up @@ -153,7 +156,10 @@ public float EstimatedMemoryUse
/// 256 colors allowed by the GIF specification). Lower values (minimum = 1) produce better
/// colors, but slow processing significantly. Higher values will speed up the quantization
/// pass at the cost of lower image quality (maximum = 100).</param>
public void Setup(bool autoAspect, int width, int height, int fps, float bufferSize, int repeat, int quality)
/// <param name="framesPerColorSample">Sample every n-th frame in a recording for color
/// mapping purposes. If framesPerColorSample is set to 0, Moments uses its default behaviour
/// and creates a brand new color palette every frame.</param>
public void Setup(bool autoAspect, int width, int height, int fps, float bufferSize, int repeat, int quality, int framesPerColorSample)
{
if (State == RecorderState.PreProcessing)
{
Expand All @@ -175,6 +181,7 @@ public void Setup(bool autoAspect, int width, int height, int fps, float bufferS
m_ReflectionUtils.ConstrainMin(x => x.m_BufferSize, bufferSize);
m_ReflectionUtils.ConstrainMin(x => x.m_Repeat, repeat);
m_ReflectionUtils.ConstrainRange(x => x.m_Quality, quality);
m_ReflectionUtils.ConstrainRange(x => x.m_FramesPerColorSample, framesPerColorSample);

// Ready to go
Init();
Expand Down
4 changes: 3 additions & 1 deletion Moments Recorder/Scripts/Worker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,13 @@ void Run()
{
m_Encoder.Start(m_FilePath);

// pass all frames to encoder to build a palette out of a subset of them
m_Encoder.BuildPalette(ref m_Frames);

for (int i = 0; i < m_Frames.Count; i++)
{
GifFrame frame = m_Frames[i];
m_Encoder.AddFrame(frame);

if (m_OnFileSaveProgress != null)
{
float percent = (float)i / (float)m_Frames.Count;
Expand Down