/// <summary> /// Handle eac3 conversions for mencoder /// TODO: This function is redundant and incorrectly written, handbrake, ffmpeg and mencoder are able to handle eac3 audio why do we need this? /// </summary> private bool ConvertMencoderEAC3() { string audioStream = ""; _jobStatus.PercentageComplete = 100; //all good by default _jobStatus.ETA = ""; if ((_videoFile.AudioCodec != "e-ac-3") && (_videoFile.AudioCodec != "eac3")) return true; // Only supports MP4, MKV and AVI if ((_extension != ".mp4") && (_extension != ".mkv") && (_extension != ".avi")) return true; _jobStatus.CurrentAction = Localise.GetPhrase("Converting E-AC3"); _jobLog.WriteEntry(this, ("Converting E-AC3"), Log.LogEntryType.Information); // Convert EAC3 file string eac3toParams; string audiop = _audioParams.Trim(); if (audiop.Contains("faac") || audiop.Contains("libfaac") || audiop.Contains("aac")) { audioStream = Path.Combine(_workingPath, Path.GetFileNameWithoutExtension(SourceVideo) + "_AUDIO.mp4"); eac3toParams = Util.FilePaths.FixSpaces(SourceVideo) + " " + Util.FilePaths.FixSpaces(audioStream) + " -384"; } else // TODO: what about other audio formats? { audioStream = Path.Combine(_workingPath, Path.GetFileNameWithoutExtension(SourceVideo) + "_AUDIO.ac3"); eac3toParams = Util.FilePaths.FixSpaces(SourceVideo) + " " + Util.FilePaths.FixSpaces(audioStream) + " -384"; } FileIO.TryFileDelete(audioStream); // Clean before starting Eac3To eac3to = new AppWrapper.Eac3To(eac3toParams, _jobStatus, _jobLog); eac3to.Run(); if (!eac3to.Success) { FileIO.TryFileDelete(audioStream); // Clean _jobLog.WriteEntry(this, ("E-AC3 conversion unsuccessful"), Log.LogEntryType.Error); _jobStatus.ErrorMsg = "E-AC3 conversion unsuccessful"; _jobStatus.PercentageComplete = 0; return false; // something went wrong } // Mux into destination if ((_extension == ".mp4") || (_extension == ".m4v")) { _jobLog.WriteEntry(this, ("Muxing E-AC3 using MP4Box"), Log.LogEntryType.Information); string mp4boxParams = " -keep-sys -keep-all -add " + FilePaths.FixSpaces(audioStream) + " " + FilePaths.FixSpaces(_convertedFile); _jobStatus.PercentageComplete = 0; //reset _jobStatus.ETA = ""; MP4Box mp4box = new MP4Box(mp4boxParams, _jobStatus, _jobLog); mp4box.Run(); if (!mp4box.Success || _jobStatus.PercentageComplete < GlobalDefs.ACCEPTABLE_COMPLETION) // check for incomplete output or process issues { FileIO.TryFileDelete(audioStream); _jobLog.WriteEntry(this, ("E-AC3 muxing using MP4Box failed at") + " " + _jobStatus.PercentageComplete.ToString(System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Error); _jobStatus.ErrorMsg = "E-AC3 muxing using MP4Box failed"; _jobStatus.PercentageComplete = 0; // something went wrong with the process return false; } } else if (_extension == ".mkv") { _jobLog.WriteEntry(this, ("Muxing E-AC3 using MKVMerge"), Log.LogEntryType.Information); string remuxedFile = Path.Combine(_workingPath, Path.GetFileNameWithoutExtension(_convertedFile) + "_REMUX.mkv"); FileIO.TryFileDelete(remuxedFile); string mkvmergeParams = "--clusters-in-meta-seek --compression -1:none " + FilePaths.FixSpaces(_convertedFile) + " --compression -1:none " + FilePaths.FixSpaces(audioStream) + " -o " + FilePaths.FixSpaces(remuxedFile); _jobStatus.PercentageComplete = 0; //reset _jobStatus.ETA = ""; MKVMerge mkvmerge = new MKVMerge(mkvmergeParams, _jobStatus, _jobLog); mkvmerge.Run(); if (!mkvmerge.Success) { FileIO.TryFileDelete(audioStream); FileIO.TryFileDelete(remuxedFile); _jobLog.WriteEntry(this, ("Muxing E-AC3 using MKVMerge failed"), Log.LogEntryType.Error); _jobStatus.ErrorMsg = "Muxing E-AC3 using MKVMerge failed"; _jobStatus.PercentageComplete = 0; // something went wrong with the process return false; } try { _jobLog.WriteEntry(this, ("Moving MKVMerge muxed E-AC3"), Log.LogEntryType.Information); FileIO.TryFileDelete(_convertedFile); File.Move(remuxedFile, _convertedFile); _jobStatus.PercentageComplete = 100; //proxy for job done since mkvmerge doesn't report _jobStatus.ETA = ""; } catch (Exception e) { FileIO.TryFileDelete(audioStream); FileIO.TryFileDelete(remuxedFile); _jobLog.WriteEntry(this, ("Unable to move MKVMerge remuxed E-AC3 file") + " " + remuxedFile + "\r\nError : " + e.ToString(), Log.LogEntryType.Error); _jobStatus.PercentageComplete = 0; _jobStatus.ErrorMsg = "Unable to move MKVMerge remuxed E-AC3 file"; return false; } } else { _jobStatus.PercentageComplete = 0; //reset _jobStatus.ETA = ""; _jobLog.WriteEntry(this, ("Muxing E-AC3 using FFMPEGRemux"), Log.LogEntryType.Information); double fps = 0; double.TryParse(_fps, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out fps); RemuxExt remuxFile = new RemuxExt(_convertedFile, _workingPath, (fps <= 0 ? _videoFile.Fps : fps), _jobStatus, _jobLog, _remuxTo); // Use output FPS if it exists otherwise the source file FPS (since it has not changed) if (remuxFile.FfmpegRemux(audioStream)) { _convertedFile = remuxFile.RemuxedFile; } else { FileIO.TryFileDelete(audioStream); _jobLog.WriteEntry(this, ("Error Muxing E-AC3 using FFMPEGRemux"), Log.LogEntryType.Error); _jobStatus.PercentageComplete = 0; _jobStatus.ErrorMsg = "Error Muxing E-AC3 using FFMPEGRemux"; return false; } } FileIO.TryFileDelete(audioStream); // Clean up _jobLog.WriteEntry(this, ("Finished EAC3 conversion, file size [KB]") + " " + (FileIO.FileSize(_convertedFile) / 1024).ToString("N", System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); return true; }
private bool MKVRemux() { _jobStatus.ErrorMsg = ""; _jobStatus.PercentageComplete = 100; //all good to start with _jobStatus.ETA = ""; Util.FileIO.TryFileDelete(RemuxedTempFile); string parameters = "--clusters-in-meta-seek -o " + FilePaths.FixSpaces(RemuxedTempFile) + " --compression -1:none " + FilePaths.FixSpaces(_originalFile); MKVMerge mkvMerge = new MKVMerge(parameters, _jobStatus, _jobLog); mkvMerge.Run(); if (!mkvMerge.Success) { _jobLog.WriteEntry(this, Localise.GetPhrase("MKVMerge failed"), Log.LogEntryType.Error); _jobStatus.ErrorMsg = Localise.GetPhrase("MKVMerge failed"); return false; } _jobLog.WriteEntry(this, Localise.GetPhrase("MKVMerge remux moving file"), Log.LogEntryType.Information); return ReplaceTempRemuxed(); }
/// <summary> /// Adds the subtitle file and chapters to the target file /// </summary> /// <param name="srtFile">Path to subtitle file</param> /// <param name="neroChapterFile">Path to Nero chapter file</param> /// <param name="xmlChapterFile">Path to xml (iTunes) chapter file</param> /// <param name="targetFile">Path to target file</param> /// <returns>False in case of an error</returns> public bool AddSubtitlesAndChaptersToFile(string srtFile, string neroChapterFile, string xmlChapterFile, string targetFile) { _jobLog.WriteEntry("Subtitle File : " + srtFile + "\nChapter File : " + neroChapterFile + "\nTarget File : " + targetFile, Log.LogEntryType.Debug); if (!File.Exists(targetFile)) return false; if (String.IsNullOrWhiteSpace(xmlChapterFile) && String.IsNullOrWhiteSpace(neroChapterFile) && String.IsNullOrWhiteSpace(srtFile)) // Atleast one file should be there to proceeed return true; // nothing to do if ((FileIO.FileSize(xmlChapterFile) <= 0) && (FileIO.FileSize(neroChapterFile) <= 0) && (FileIO.FileSize(srtFile) < 0)) // Atleast one file should be valid to proceeed return true; // nothing to do string parameters = ""; switch (FilePaths.CleanExt(targetFile)) { case ".mp4": case ".m4v": if (File.Exists(srtFile)) // Add the subtitles parameters += " -add " + Util.FilePaths.FixSpaces(srtFile) + ":hdlr=sbtl"; if (File.Exists(neroChapterFile)) // Add the nero chapters parameters += " -chap " + Util.FilePaths.FixSpaces(neroChapterFile); if (File.Exists(xmlChapterFile)) // Add the iTunes chapters TODO: adding ttxt chapter files leads to incorrect file length (minutes) reported, why is MP4Box doing this? Is the TTXT format incorrect? parameters += " -add " + Util.FilePaths.FixSpaces(xmlChapterFile) + ":chap"; parameters += " " + Util.FilePaths.FixSpaces(targetFile); // output file MP4Box mp4Box = new MP4Box(parameters, _jobStatus, _jobLog, _ignoreSuspend); mp4Box.Run(); if (!mp4Box.Success || (FileIO.FileSize(targetFile) <= 0)) { _jobStatus.PercentageComplete = 0; _jobStatus.ErrorMsg = "Mp4Box adding subtitles failed"; _jobLog.WriteEntry(Localise.GetPhrase("Mp4Box adding subtitles failed"), Log.LogEntryType.Error); ; return false; } return true; // all done case ".mkv": string outputFile = FilePaths.GetFullPathWithoutExtension(targetFile) + "-temp.mkv"; parameters += "--clusters-in-meta-seek -o " + Util.FilePaths.FixSpaces(outputFile) + " --compression -1:none " + Util.FilePaths.FixSpaces(targetFile); // output file if (File.Exists(srtFile)) // Add the subtitles parameters += " --compression -1:none " + Util.FilePaths.FixSpaces(srtFile); if (File.Exists(neroChapterFile)) // Add the chapters parameters += " --compression -1:none --chapters " + Util.FilePaths.FixSpaces(neroChapterFile); MKVMerge mkvMerge = new MKVMerge(parameters, _jobStatus, _jobLog, _ignoreSuspend); mkvMerge.Run(); if (!mkvMerge.Success || (Util.FileIO.FileSize(outputFile) <= 0)) // check for +ve success { _jobStatus.PercentageComplete = 0; _jobStatus.ErrorMsg = "MKVMerge adding subtitles failed"; _jobLog.WriteEntry(Localise.GetPhrase("MKVMerge adding subtitles failed"), Log.LogEntryType.Error); ; return false; } // Replace the temp file Util.FileIO.TryFileReplace(targetFile, outputFile); if (Util.FileIO.FileSize(targetFile) <= 0) { _jobLog.WriteEntry(Localise.GetPhrase("MKVMerge: Error moving files"), Log.LogEntryType.Error); ; return false; // Something went wrong } return true; // done default: return true; // not a valid type, so ignore it } }
/// <summary> /// Remove commercials from MKV files useing MKVMerge /// </summary> private void CutMKV() { List<KeyValuePair<float, float>> keepList = new List<KeyValuePair<float, float>>(); string tempFile = CutFileName(_uncutVideo, 0, 0); // Read the EDL file and convert into MKVMerge cut structure if (!ParseEDLFile(ref keepList)) return; // Create the MKV splits //Do the cuts and pick them up as we go int cutNumber = 0; IEnumerable<string> newFilesFound = new List<string>(); // Build the list of timecodes to split into invidiual files string Parameters = "--clusters-in-meta-seek --split parts:"; foreach (KeyValuePair<float, float> keep in keepList) { _jobLog.WriteEntry(this, Localise.GetPhrase("CutMKV: Found commercials from video - segment") + " " + cutNumber.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Debug); TimeSpan startCut = TimeSpan.FromSeconds(Convert.ToDouble(keep.Key.ToString(CultureInfo.InvariantCulture))); TimeSpan endCut = TimeSpan.FromSeconds(Convert.ToDouble(keep.Value.ToString(CultureInfo.InvariantCulture))); if (cutNumber == 0) Parameters += startCut.ToString() + "-" + endCut.ToString(); else Parameters += ",+" + startCut.ToString() + "-" + endCut.ToString(); cutNumber++; } Parameters += " --compression -1:none " + Util.FilePaths.FixSpaces(_uncutVideo) + " -o " + Util.FilePaths.FixSpaces(tempFile); if (cutNumber < 1) { _jobLog.WriteEntry(this, Localise.GetPhrase("No commercials to remove from ") + EDLFile, Log.LogEntryType.Information); _jobStatus.PercentageComplete = 100; //Set to success since sometime mp4box doesn't set to 100 if there no/incomplete pieces to strip return; } _jobStatus.CurrentAction = Localise.GetPhrase("Cutting commercials from video"); MKVMerge mkvMerge = new MKVMerge(Parameters, _jobStatus, _jobLog); mkvMerge.Run(); if (!mkvMerge.Success || (Util.FileIO.FileSize(tempFile) <= 0)) // check for +ve success { _jobStatus.PercentageComplete = 0; _jobStatus.ErrorMsg = "CutMKV merging video segments failed"; _jobLog.WriteEntry(this, Localise.GetPhrase("CutMKV merging video segments failed"), Log.LogEntryType.Error); ; return; } // Move the files _jobLog.WriteEntry(this, Localise.GetPhrase("CutMKV trying to replace file") + " Output : " + _uncutVideo + " Temp : " + tempFile, Log.LogEntryType.Debug); RenameAndMoveFile(tempFile); }