public static Bitmap GetMapBitmap(Int32 picWidth, Int32 picHeight, VideoFrameList vfl, Int32 value, Decimal threshold) { Bitmap bmpMap = new Bitmap(picWidth, picHeight); Graphics g = Graphics.FromImage(bmpMap); Int32 startFrameNum = value * picWidth; Int32 endFrameNum = (value + 1) * picWidth; Int32 currentXPixel = 0; for (int i = startFrameNum; i < endFrameNum; i++) { if (i > vfl.Count - 1) { g.DrawLine(Pens.Black, currentXPixel, 0, currentXPixel, bmpMap.Height); currentXPixel++; continue; } if (vfl.FrameList[i].FrameDifferenceFromPrevious <= threshold) { g.DrawLine(Pens.Red, currentXPixel, 0, currentXPixel, bmpMap.Height); } else { g.DrawLine(Pens.Blue, currentXPixel, 0, currentXPixel, bmpMap.Height); } currentXPixel++; } return(bmpMap); }
/// <summary> /// Write a section file from a Video frame list /// </summary> /// <param name="vfl">The video frame list that contains the sections to be written</param> /// <param name="filename">the section file name</param> public static void WriteSections(VideoFrameList vfl, String filename) { StreamWriter sw = new StreamWriter(filename, false, AcHelper.FindEncoding("1253")); foreach (VideoFrameSection vfs in vfl.FrameSections) { sw.WriteLine(vfs.StringForFile()); } sw.Close(); }
private void btnNewTimecodesFile_Click(object sender, EventArgs e) { try { clearHeader(); clearFrameList(); txtTimecodesFile.Text = String.Empty; vfl = new VideoFrameList(); } catch (Exception ex) { ShowExceptionMessage(ex, "Error setting new timecodes file!"); } }
/// <summary> /// Calculates a bitmap for a timecodes map according to a video frame list /// </summary> /// <param name="vfl"></param> /// <param name="steps"></param> /// <param name="value"></param> /// <returns></returns> public static Bitmap GetMapBitmap(Int32 picWidth, Int32 picHeight, VideoFrameList vfl, Int32 value) { Bitmap bmpMap = new Bitmap(picWidth, picHeight); Graphics g = Graphics.FromImage(bmpMap); Int32 startFrameNum = value * picWidth; Int32 endFrameNum = (value + 1) * picWidth; Int32 currentXPixel = 0; for (int i = startFrameNum; i < endFrameNum; i++) { if (i > vfl.Count - 1) { g.DrawLine(Pens.Black, currentXPixel, 0, currentXPixel, bmpMap.Height); currentXPixel++; continue; } Decimal currentFramerate = vfl.FrameList[i].FrameRate; if (currentFramerate >= 23.0m && currentFramerate <= 24.0m) { g.DrawLine(Pens.Blue, currentXPixel, 0, currentXPixel, bmpMap.Height); } else if (currentFramerate >= 29.0m && currentFramerate <= 30.0m) { g.DrawLine(Pens.ForestGreen, currentXPixel, 0, currentXPixel, bmpMap.Height); } else if (currentFramerate >= 59.0m && currentFramerate <= 60.0m) { g.DrawLine(Pens.Orange, currentXPixel, 0, currentXPixel, bmpMap.Height); } else if (currentFramerate >= 14.0m && currentFramerate <= 16.0m) { g.DrawLine(Pens.White, currentXPixel, 0, currentXPixel, bmpMap.Height); } else { g.DrawLine(Pens.Red, currentXPixel, 0, currentXPixel, bmpMap.Height); } currentXPixel++; } return(bmpMap); }
/// <summary> /// Function to analyse a string line of a v1 timecodes file /// </summary> /// <param name="frame">string which contains a valid line</param> /// <param name="vfl">the video frame list to write to</param> private void AnalyseV1(String frame, VideoFrameList vfl) { //Get elements //elements[0] first frame //elememts[1] last frame //elements[2] framerate String[] elements = frame.Split(new String[] { "," }, StringSplitOptions.None); //check for valid elements if (elements.Length == 3) { //Calculate FrameInfo data int start = Convert.ToInt32(elements[0]); int end = Convert.ToInt32(elements[1]); for (int i = start; i <= end; i++) { VideoFrame tmp = new VideoFrame(); tmp.FrameNumber = i; tmp.FrameRate = AcHelper.DecimalParse(elements[2]); if (i == 0) { tmp.FrameStartTime = 0.0m; } else { tmp.FrameStartTime = vfl.FrameList[i - 1].FrameDuration + vfl.FrameList[i - 1].FrameStartTime; } //Add FrameInfo to FrameList vfl.Add(tmp); } } else { throw (new AcException("Invalid format v1 timecodes!")); } }
public void CreateFromSections(String sectionsFile, String chaptersFile, Decimal frameRate, Boolean useChapters, Boolean isTrimFile) { //clear chapters chapterList.Clear(); //If use chapters, load chapter file if (useChapters) { if (AcHelper.GetFilename(chaptersFile, GetFileNameMode.ExtensionOnly, GetDirectoryNameMode.NoPath).ToLowerInvariant() == "xml") { Load(ChapterType.XML, chaptersFile); } else if (AcHelper.GetFilename(chaptersFile, GetFileNameMode.ExtensionOnly, GetDirectoryNameMode.NoPath).ToLowerInvariant() == "txt") { Load(ChapterType.OGM, chaptersFile); } } //Create a Videoframelist vfl = new VideoFrameList(); //Load the sections file SectionParser.ParseSections(sectionsFile, vfl); //Sanity check if (useChapters && vfl.CountSections != chapterList.Count) { throw new AcException("Error creating chapters! Sections count is different from the chapters count!"); } if (isTrimFile) { Int32 framesToDelete = 0; for (Int32 i = 0; i < vfl.CountSections; i++) { //If no chapters are loaded if (!useChapters) { //Create new empty chapter VideoChapter chap = new VideoChapter(); chapterList.Add(chap); } if (i == 0) { Int32 start = 0; Int32 end = vfl.FrameSections[i].FrameEnd; framesToDelete = vfl.FrameSections[0].FrameStart; end -= framesToDelete; chapterList[i].StartTime = VideoFrame.FrameTimeFromFrameNumber(start, frameRate, FrameFromType.FromFrameRate); chapterList[i].EndTime = VideoFrame.FrameTimeFromFrameNumber(Convert.ToDecimal(end) + 0.5m, frameRate, FrameFromType.FromFrameRate); } else { Int32 start = vfl.FrameSections[i].FrameStart; Int32 end = vfl.FrameSections[i].FrameEnd; Int32 prevEnd = vfl.FrameSections[i - 1].FrameEnd; framesToDelete += start - prevEnd - 1; start -= framesToDelete; end -= framesToDelete; chapterList[i].StartTime = VideoFrame.FrameTimeFromFrameNumber(Convert.ToDecimal(start) + 0.5m, frameRate, FrameFromType.FromFrameRate); chapterList[i].EndTime = VideoFrame.FrameTimeFromFrameNumber(Convert.ToDecimal(end) + 0.5m, frameRate, FrameFromType.FromFrameRate); } } } else { for (Int32 i = 0; i < vfl.CountSections; i++) { //If no chapters are loaded if (!useChapters) { //Create new empty chapter VideoChapter chap = new VideoChapter(); chapterList.Add(chap); } Int32 start = vfl.FrameSections[i].FrameStart; Int32 end = vfl.FrameSections[i].FrameEnd; chapterList[i].StartTime = VideoFrame.FrameTimeFromFrameNumber(Convert.ToDecimal(start) + 0.5m, frameRate, FrameFromType.FromFrameRate); chapterList[i].EndTime = VideoFrame.FrameTimeFromFrameNumber(Convert.ToDecimal(end) + 0.5m, frameRate, FrameFromType.FromFrameRate); } } }
private void btnSyncAss_Click(object sender, EventArgs e) { try { AssParser assP = new AssParser(); assP.ParseASS(txtAssFile.Text); VideoFrameList vfl = _Kienzan.VideoFrames; //Double framerate = AcHelper.ConvertToDouble(Convert.ToString(comTargetFramerate.SelectedItem)); foreach (AssDialogue assD in assP.AssContents) { Decimal timeToDelete = 0m; for (Int32 currentSection = 0; currentSection < vfl.FrameSections.Count; currentSection++) { VideoFrameSection vfs = vfl.FrameSections[currentSection]; Decimal startSection = vfl.FrameList[vfs.FrameStart].FrameStartTime; Decimal endSection = vfl.FrameList[vfs.FrameEnd].FrameEndTime; //Check if the sub ends before the section if (assD.time_end_double <= startSection) { assD.deleted = true; break; } //Check if the sub starts after the section if (assD.time_start_double >= endSection) { //If its the last sections, then delete the sub if (currentSection == vfl.FrameSections.Count - 1) { assD.deleted = true; break; } else { if (currentSection == 0) { timeToDelete = startSection; } else { Decimal start = startSection; Decimal end = endSection; Decimal prevEnd = vfl.FrameList[vfl.FrameSections[currentSection - 1].FrameEnd].FrameEndTime; timeToDelete += start - prevEnd; } continue; } } //Time to resync the sub if (currentSection == 0) { TimeSpan ts; timeToDelete = startSection; assD.time_start_double = assD.time_start_double - timeToDelete; ts = TimeSpan.FromMilliseconds(Convert.ToDouble(assD.time_start_double)); assD.time_start = ts.Hours.ToString("0") + ":" + ts.Minutes.ToString("00") + ":" + ts.Seconds.ToString("00") + "." + ts.Milliseconds.ToString("00"); assD.time_end_double = assD.time_end_double - timeToDelete; ts = TimeSpan.FromMilliseconds(Convert.ToDouble(assD.time_end_double)); assD.time_end = ts.Hours.ToString("0") + ":" + ts.Minutes.ToString("00") + ":" + ts.Seconds.ToString("00") + "." + ts.Milliseconds.ToString("00"); break; } else { TimeSpan ts; Decimal start = startSection; Decimal end = endSection; Decimal prevEnd = vfl.FrameList[vfl.FrameSections[currentSection - 1].FrameEnd].FrameEndTime; timeToDelete += start - prevEnd; assD.time_start_double = assD.time_start_double - timeToDelete; ts = TimeSpan.FromMilliseconds(Convert.ToDouble(assD.time_start_double)); assD.time_start = ts.Hours.ToString("0") + ":" + ts.Minutes.ToString("00") + ":" + ts.Seconds.ToString("00") + "." + (ts.Milliseconds / 10).ToString("00"); assD.time_end_double = assD.time_end_double - timeToDelete; ts = TimeSpan.FromMilliseconds(Convert.ToDouble(assD.time_end_double)); assD.time_end = ts.Hours.ToString("0") + ":" + ts.Minutes.ToString("00") + ":" + ts.Seconds.ToString("00") + "." + (ts.Milliseconds / 10).ToString("00"); break; } } } assP.WriteFinalAss(txtAssFile.Text.Substring(0, txtAssFile.Text.LastIndexOf(".")) + ".resync.ass"); ShowSuccessMessage("Resync complete!"); } catch (Exception ex) { ShowExceptionMessage(ex); } }
/// <summary> /// Function to parse timecodes file /// </summary> /// <param name="timecodeFile">the path for the timecode file to parse</param> /// <param name="vfl">the video frame list to write to</param> /// <param name="writeDump">flag whether to write dump file</param> public void ParseTimecodes(String timecodeFile, VideoFrameList vfl, Boolean writeDump) { String curLine = ""; String prevLine = ""; bool isV1 = false; bool isV2 = false; Decimal assumedFps = 0.0m; //Open timecodes file using (StreamReader reader = new StreamReader(timecodeFile, Encoding.UTF8)) { try { //Start timing //Stopwatch timer = new Stopwatch(); //timer.Start(); //AcLogger.Log("Starting Parsing Timecodes file : " + timecodeFile, AcLogger.AcLogType.Form); //Read timecodes file while ((curLine = reader.ReadLine()) != null) { //Check for comment lines if (curLine.StartsWith("#")) { if (curLine.ToLower().Contains("v1")) { //AcLogger.Log("Version 1 Timecodes File Detected", AcLogger.AcLogType.Form); isV1 = true; timecodesFileVersion = 1; } if (curLine.ToLower().Contains("v2")) { //AcLogger.Log("Version 2 Timecodes File Detected", AcLogger.AcLogType.Form); isV2 = true; timecodesFileVersion = 2; } } //Check for assume line else if (curLine.ToLower().Contains("assume")) { curLine = curLine.ToLower().Replace("assume", "").Replace(" ", ""); assumedFps = AcHelper.DecimalParse(curLine); assumedFrameRate = assumedFps; //AcLogger.Log("Assumed FPS : " + assumedFps, AcLogger.AcLogType.Form); } else { //Check for empty line if (String.IsNullOrWhiteSpace(curLine)) { //Do nothing continue; } if (isV1) { AnalyseV1(curLine, vfl); } if (isV2) { //First Frame if (String.IsNullOrWhiteSpace(prevLine)) { prevLine = reader.ReadLine(); vfl.Add(AnalyseV2(curLine, prevLine, 0)); } //Other Frames else { vfl.Add(AnalyseV2(prevLine, curLine, vfl.Count)); prevLine = curLine; } } } } //Calculate last frame's FrameInfo data if v2 timecodes if (isV2) { vfl.Add(new VideoFrame() { FrameNumber = vfl.Count, FrameStartTime = AcHelper.DecimalParse(prevLine), FrameDuration = vfl.FrameList[vfl.Count - 1].FrameDuration }); } //timer.Stop(); } catch (Exception ex) { throw (new AcException("Error in reading timecodes file!", ex)); } } //AcLogger.Log("Parsing Timecodes finished!", AcLogger.AcLogType.Form); //AcLogger.Log("Parsing took : " + timer.Elapsed, AcLogger.AcLogType.Form); //AcLogger.Log("Total Frames : " + vfl.Count, AcLogger.AcLogType.Form); //Check timecode dump if (writeDump) { try { //Write Timecode Dump StringBuilder dumpBuilder = new StringBuilder(); using (StreamWriter writer = new StreamWriter(timecodeFile + ".dmp", false, Encoding.UTF8)) { for (int i = 0; i < vfl.Count; i++) { dumpBuilder.AppendFormat("Frame_Number:{0} Frame_Fps:{1} Frame_Duration:{2}\r\n", vfl.FrameList[i].FrameNumber, vfl.FrameList[i].FrameRate, vfl.FrameList[i].FrameDuration); } writer.Write(dumpBuilder.ToString()); } } catch (Exception ex) { throw (new AcException("Error writing timecode dump!", ex)); } } }
/// <summary> /// Function to parse duplicates file /// </summary> /// <param name="dupFile"> /// String with the path of the duplicates file /// </param> public static void ParseDup(String dupFile, VideoFrameList vfl) { using (StreamReader sr = new StreamReader(dupFile, Encoding.UTF8)) { //Start timing //Stopwatch timer = new Stopwatch(); //timer.Start(); //AcLogger.Log("Starting Parsing Duplicates file : " + dupFile, AcLogger.AcLogType.Form); //Check if FrameList exists bool createList = (vfl.Count == 0); //Read file String line = ""; Int32 frameNum = 0; while ((line = sr.ReadLine()) != null) { //Check for first line if (line.ToLowerInvariant().StartsWith("dedup")) { //Do nothing and advance to the next line continue; } //Check for frame difference line else if (line.ToLowerInvariant().StartsWith("frm")) { //Get frame difference String frameDiff = ""; int start = line.IndexOf("="); int len = line.IndexOf("%") - start; frameDiff = line.Substring(start + 1, len).Trim(); frameDiff = frameDiff.Substring(0, frameDiff.Length - 1); //Check if new frame list if (createList) { //Create new Video frame object VideoFrame tmpFrm = new VideoFrame(); tmpFrm.FrameNumber = frameNum; tmpFrm.FrameDifferenceFromPrevious = AcHelper.DecimalParse(frameDiff); //Add it to list vfl.Add(tmpFrm); } else { //Check if frame numbers don't match with the existing list if (frameNum > vfl.Count - 1) { //Invalid dup file throw (new AcException("Invalid Dup File! Frames are inconsistent with existing data!")); } else { //Set the difference vfl.FrameList[frameNum].FrameDifferenceFromPrevious = AcHelper.DecimalParse(frameDiff); } } //Advance frame number counter frameNum++; } } //timer.Stop(); //AcLogger.Log("Parsing Timecodes finished!", AcLogger.AcLogType.Form); //AcLogger.Log("Total frames : " + frameNum, AcLogger.AcLogType.Form); //AcLogger.Log("Parsing took : " + timer.Elapsed, AcLogger.AcLogType.Form); } }
private void btnSplit_Click(object sender, EventArgs e) { try { AssParser assP = new AssParser(); assP.ParseASS(txtAssFile.Text); VideoFrameList vfl = new VideoFrameList(); SectionParser.ParseSections(txtSectionsFile.Text, vfl); Decimal framerate = AcHelper.DecimalParse(txtFramerate.Text); foreach (AssDialogue assD in assP.AssContents) { Decimal timeToDelete = 0; for (Int32 currentSection = 0; currentSection < vfl.FrameSections.Count; currentSection++) { VideoFrameSection vfs = vfl.FrameSections[currentSection]; Decimal startSection = VideoFrame.GetStartTimeFromFrameNumber(vfs.FrameStart, framerate); Decimal endSection = VideoFrame.GetStartTimeFromFrameNumber(vfs.FrameEnd, framerate); //Check if the sub ends before the section if (assD.time_end_double <= startSection) { assD.deleted = true; break; } //Check if the sub starts after the section if (assD.time_start_double >= endSection) { //If its the last sections, then delete the sub if (currentSection == vfl.FrameSections.Count - 1) { assD.deleted = true; break; } else { continue; } } //Time to resync the sub if (currentSection == 0) { TimeSpan ts; timeToDelete = startSection; assD.time_start_double = assD.time_start_double - timeToDelete; ts = TimeSpan.FromMilliseconds(Convert.ToDouble(assD.time_start_double)); assD.time_start = ts.Hours.ToString("0") + ":" + ts.Minutes.ToString("00") + ":" + ts.Seconds.ToString("00") + "." + ts.Milliseconds.ToString("00"); assD.time_end_double = assD.time_end_double - timeToDelete; ts = TimeSpan.FromMilliseconds(Convert.ToDouble(assD.time_end_double)); assD.time_end = ts.Hours.ToString("0") + ":" + ts.Minutes.ToString("00") + ":" + ts.Seconds.ToString("00") + "." + ts.Milliseconds.ToString("00"); break; } else { TimeSpan ts; Decimal start = startSection; Decimal end = endSection; Decimal prevEnd = VideoFrame.GetStartTimeFromFrameNumber(vfl.FrameSections[currentSection - 1].FrameEnd, framerate); timeToDelete += start - prevEnd - VideoFrame.GetDurationFromFrameRate(framerate); assD.time_start_double = assD.time_start_double - timeToDelete; ts = TimeSpan.FromMilliseconds(Convert.ToDouble(assD.time_start_double)); assD.time_start = ts.Hours.ToString("0") + ":" + ts.Minutes.ToString("00") + ":" + ts.Seconds.ToString("00") + "." + ts.Milliseconds.ToString("00"); assD.time_end_double = assD.time_end_double - timeToDelete; ts = TimeSpan.FromMilliseconds(Convert.ToDouble(assD.time_end_double)); assD.time_end = ts.Hours.ToString("0") + ":" + ts.Minutes.ToString("00") + ":" + ts.Seconds.ToString("00") + "." + ts.Milliseconds.ToString("00"); break; } } } assP.WriteFinalAss(txtAssFile.Text.Substring(0, txtAssFile.Text.LastIndexOf(".") - 1) + ".resync.ass"); MessageBox.Show("Resync complete!", "Success!"); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error!"); } }
/// <summary> /// Function to parse the trims file /// </summary> /// <param name="sectionsFile"> /// String with the path of the trims file /// </param> public static void ParseSections(String sectionsFile, VideoFrameList vfl) { StreamReader sr; String line = ""; try { //Open trims file sr = new StreamReader(sectionsFile, Encoding.UTF8); } catch (Exception ex) { throw (new AcException("Error opening trims file!", ex)); } try { //Read file while ((line = sr.ReadLine()) != null) { //Check for Avisynth style trims if (line.ToLowerInvariant().Contains("trim") && !(line.StartsWith("#"))) { String tmp = line.ToLowerInvariant().Substring(line.IndexOf("trim", StringComparison.InvariantCultureIgnoreCase)); tmp = tmp.ToLowerInvariant().Substring(tmp.IndexOf("(") + 1); tmp = tmp.Substring(0, tmp.IndexOf(")")); tmp = tmp.Trim(); VideoFrameSection vfsTmp = new VideoFrameSection(); if (line.Contains("=")) { vfsTmp.SectionName = line.Substring(0, line.IndexOf("=")).Trim(); } String[] elements = tmp.Split(new String[] { "," }, StringSplitOptions.None); //Check trim's form //1. trim(clip,start,end) //2. trim(start,end) if (elements.Length == 3) { vfsTmp.FrameStart = Convert.ToInt32(elements[1].Trim()); vfsTmp.FrameEnd = Convert.ToInt32(elements[2].Trim()); vfl.FrameSections.Add(vfsTmp); } else if (elements.Length == 2) { vfsTmp.FrameStart = Convert.ToInt32(elements[0].Trim()); vfsTmp.FrameEnd = Convert.ToInt32(elements[1].Trim()); vfl.FrameSections.Add(vfsTmp); } else { //No valid format found, write to debug //AcLogger.Log(new AcException("Invalid Trim format!"), AcLogger.AcLogType.Form); } } //Check for simple text trims else if (line.Contains(",") || line.Contains("-")) { try { //Check if starts with number Int32 chkTmp = 0; if (Int32.TryParse(line.Substring(0, 1), out chkTmp)) { //if starts with number check if it contains comments (#) if (line.Contains("#")) { line = line.Substring(0, line.IndexOf("#")); line = line.Trim(); } VideoFrameSection vfsTmp = new VideoFrameSection(); String[] elements = new String[] { "" }; if (line.Contains(",")) { elements = line.Split(new String[] { "," }, StringSplitOptions.None); } else if (line.Contains("-")) { elements = line.Split(new String[] { "-" }, StringSplitOptions.None); } //Check trim's form //1. trim(clip,start,end) //2. trim(start,end) if (elements.Length == 3) { vfsTmp.FrameStart = Convert.ToInt32(elements[1].Trim()); vfsTmp.FrameEnd = Convert.ToInt32(elements[2].Trim()); vfl.FrameSections.Add(vfsTmp); } else if (elements.Length == 2) { vfsTmp.FrameStart = Convert.ToInt32(elements[0].Trim()); vfsTmp.FrameEnd = Convert.ToInt32(elements[1].Trim()); vfl.FrameSections.Add(vfsTmp); } else { //No valid format found, write to debug //AcLogger.Log(new AcException("Invalid Trim format!"), AcLogger.AcLogType.Form); } } } catch (Exception ex) { Debug.WriteLine(ex); //No valid format found, write to debug //AcLogger.Log(new AcException("Invalid Trim format!", ex), AcLogger.AcLogType.Form); } } } } catch (Exception ex) { sr.Close(); throw (new AcException("Error in reading trims file!", ex)); } try { //Close File sr.Close(); } catch (Exception ex) { throw (new AcException("Error in closing trims file!", ex)); } }