using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using Emgu.CV; using FFMpegCore; using FFMpegCore.Enums; using FFMpegCore.Helpers; using ImageMagick; using UnityEngine; using UnityEngine.UI; public class AlreadyGreenedImage { public Texture2D original; public Texture2D greenedImage; public AlreadyGreenedImage(Texture2D nOg, Texture2D nGImg) { original = nOg; greenedImage = nGImg; } public AlreadyGreenedImage() { } } public class CharRenderer : MonoBehaviour { [HideInInspector] public List renderedTextures = new List(); public int framesPerSecond = 30; public GameObject loadingBarParent; public Slider progressBar; public Text whatIsLoading; private string loadingTextBase = "Currently Loading: \n"; private Size currentSize; public bool greenScreen; private List greenedImages; private List textureMats; private string videoFileExtension = "mov"; private void Start() { loadingBarParent.SetActive(false); } public void SetGreenScreen(bool green) { greenScreen = green; } public void SelectFileToSaveRender() { Stream stream; videoFileExtension = greenScreen ? "mp4" : "mov"; System.Windows.Forms.SaveFileDialog sfd = new System.Windows.Forms.SaveFileDialog(); string title = "Select where to put your rendered gif"; sfd.Title = title; sfd.Filter = $"{videoFileExtension} (*.{videoFileExtension}) | *.{videoFileExtension}"; sfd.FilterIndex = 1; if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { stream = sfd.OpenFile(); if (stream != null) { FileStream file = stream as FileStream; if (file != null) { RenderByFiles(file.Name); } stream.Close(); } } } public void RenderByFiles(string path) { renderedTextures.Clear(); loadingBarParent.SetActive(true); whatIsLoading.text = loadingTextBase + "Starting"; progressBar.minValue = 0; progressBar.value = 0; int maxValue = 0; maxValue = InfoSingleton.Instance.talker.source.clip.samples / (InfoSingleton.Instance.talker.source.clip.frequency / framesPerSecond); maxValue += 2; progressBar.maxValue = maxValue; textureMats = new List(); greenedImages = new List(); StartCoroutine(RenderCouritine(path)); } IEnumerator RenderCouritine(string path) { List imagePathList = new List(); currentSize = new Size(InfoSingleton.Instance.talker.ReturnCharImageOnPPos(0).width, InfoSingleton.Instance.talker.ReturnCharImageOnPPos(0).height); int num = 0; string temporalFilesPath = path.Substring(0,path.LastIndexOf("\\")); print("temporalFiles " + temporalFilesPath); print("Starting render"); for (int i = 0; i < InfoSingleton.Instance.talker.source.clip.samples; i = i + InfoSingleton.Instance.talker.source.clip.frequency/framesPerSecond) { print("Rendering image number " + num); whatIsLoading.text = loadingTextBase + "Rendering image number " + num; Texture2D starter = InfoSingleton.Instance.talker.ReturnCharImageOnPPos(i); Texture2D beingSaved; if (greenScreen) { AlreadyGreenedImage alreadyGreen = greenedImages.Find(x => x.original == starter); if (alreadyGreen != null) { beingSaved = alreadyGreen.greenedImage; } else { beingSaved = FromTransparentToColor(starter, new UnityEngine.Color(0, 1, 0, 1)); } } else { beingSaved = starter; } renderedTextures.Add(beingSaved); byte[] tempImageData = beingSaved.EncodeToPNG(); Mat nMat = new Mat(); CvInvoke.Imdecode(tempImageData,Emgu.CV.CvEnum.ImreadModes.Unchanged,nMat); textureMats.Add(nMat); string numberStringed = num.ToString("000"); System.IO.File.WriteAllBytes(temporalFilesPath + "\\imagenNumero-" + numberStringed + ".png", tempImageData); imagePathList.Add(temporalFilesPath + "\\imagenNumero-" + numberStringed + ".png"); num++; progressBar.value += 1; yield return new WaitForSeconds(0.01f); } if(imagePathList.Count > 0) { progressBar.value += 1; string whichCodec = greenScreen ? "libx264" : "prores_ks"; TurnImagesToFFMpeg(path,imagePathList, whichCodec); } else { //TODO ERROR POPUP loadingBarParent.SetActive(false); } } private void TurnImagesToFFMpeg(string savePath, List imagePathList,string codec) { var video = JoinImageSequenceWithCodec(savePath, codec, framesPerSecond,imagePathList.ToArray()); //FFMpegArguments.FromFileInput(imagePathList.ToArray(),false,options => options.WithFramerate(framesPerSecond). //WithVideoCodec(FFMpeg.GetCodec("apcn"))).OutputToFile(savePath); foreach (string path in imagePathList) { System.IO.File.Delete(path); } FFMpeg.ReplaceAudio(savePath,InfoSingleton.Instance.audioPath,savePath); progressBar.value += 1; whatIsLoading.text = loadingTextBase + "Images turned into video"; loadingBarParent.SetActive(false); } private Texture2D FromTransparentToColor(Texture2D starter, UnityEngine.Color selectedColor) { Texture2D toReturn = starter; for (int x = 0; x < currentSize.Width; x++) { for (int y = 0; y < currentSize.Height; y++) { UnityEngine.Color pixelColor = toReturn.GetPixel(x, y); if (pixelColor.a <= 0f) { toReturn.SetPixel(x, y, selectedColor); } else if(pixelColor.a > 0 && pixelColor.a <= 1f) { toReturn.SetPixel(x, y, new UnityEngine.Color(pixelColor.r,pixelColor.g,pixelColor.b,1)); } } } return toReturn; } //Get audio //string audioPath = "F:\\PruebaAutoHablador\\1\\extractedAudio.wav"; //print("Extracting audio"); //float[] samples = new float[InfoSingleton.Instance.talker.source.clip.samples]; //InfoSingleton.Instance.talker.source.clip.GetData(samples, 0); //byte[] audioData = BitConverter.DoubleToInt64Bits(samples); //print("Adding audio"); //FFMpeg.ReplaceAudio("F:\\PruebaAutoHablador\\1\\joinedVideo.mp4",audioPath, "F:\\PruebaAutoHablador\\1\\joinedVideo.mp4"); //MemoryStream imgStream = new MemoryStream(tempImageData); //Bitmap imageMap = new Bitmap(imgStream); //System.Drawing.Image img = System.Drawing.Image.FromStream(imgStream); //System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(imageMap); ////TODO add color selection //g.Clear(System.Drawing.Color.FromArgb(255,0,255,0)); //g.DrawImageUnscaled(img,0,0); //byte[] finalImage = (byte[])new ImageConverter().ConvertTo(imageMap, typeof(byte[])); public bool JoinImageSequenceWithCodec(string output, string videoCodec, double frameRate = 30, params string[] images) { var fileExtensions = images.Select(Path.GetExtension).Distinct().ToArray(); if (fileExtensions.Length != 1) { throw new ArgumentException("All images must have the same extension", nameof(images)); } var fileExtension = fileExtensions[0].ToLowerInvariant(); int? width = null, height = null; var tempFolderName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, Guid.NewGuid().ToString()); Directory.CreateDirectory(tempFolderName); try { var index = 0; foreach (var imagePath in images) { var analysis = FFProbe.Analyse(imagePath); FFMpegHelper.ConversionSizeExceptionCheck(analysis.PrimaryVideoStream!.Width, analysis.PrimaryVideoStream!.Height); width ??= analysis.PrimaryVideoStream.Width; height ??= analysis.PrimaryVideoStream.Height; var destinationPath = Path.Combine(tempFolderName, $"{index++.ToString().PadLeft(9, '0')}{fileExtension}"); File.Copy(imagePath, destinationPath); } return FFMpegArguments .FromFileInput(Path.Combine(tempFolderName, $"%09d{fileExtension}"), false, options => options .WithFramerate(frameRate)) .OutputToFile(output, true, options => options .Resize(width!.Value, height!.Value) .WithFramerate(frameRate).WithVideoCodec(videoCodec).WithVariableBitrate(25)) .ProcessSynchronously(); } finally { Directory.Delete(tempFolderName, true); } } }