private static String ConstructTrackOrder(VideoFileInfo videoFile) { List<Int32>trackNumbers = new List<Int32>(videoFile.Tracks.Count); videoFile.Tracks.Where(t => t.TrackType == TrackType.Video) .OrderBy(t => t.MkvToolsTrackNumber) .ToList().ForEach(t => trackNumbers.Add(t.MkvToolsTrackNumber)); videoFile.Tracks.Where(t => t.TrackType == TrackType.Audio && t.Default == true) .OrderBy(t => t.MkvToolsTrackNumber) .ToList().ForEach(t => trackNumbers.Add(t.MkvToolsTrackNumber)); videoFile.Tracks.Where(t => t.TrackType == TrackType.Audio && t.Default == false) .OrderBy(t => t.MkvToolsTrackNumber) .ToList().ForEach(t => trackNumbers.Add(t.MkvToolsTrackNumber)); videoFile.Tracks.Where(t => t.TrackType == TrackType.Subtitle && t.Default == true) .OrderBy(t => t.MkvToolsTrackNumber) .ToList().ForEach(t => trackNumbers.Add(t.MkvToolsTrackNumber)); videoFile.Tracks.Where(t => t.TrackType == TrackType.Subtitle && t.Default == false) .OrderBy(t => t.MkvToolsTrackNumber) .ToList().ForEach(t => trackNumbers.Add(t.MkvToolsTrackNumber)); videoFile.Tracks.Where(t => t.TrackType == TrackType.Other) .OrderBy(t => t.MkvToolsTrackNumber) .ToList().ForEach(t => trackNumbers.Add(t.MkvToolsTrackNumber)); StringBuilder mkvMergeTrackOrder = new StringBuilder(); trackNumbers.ForEach(n => mkvMergeTrackOrder.AppendFormat("0:{0},", n)); mkvMergeTrackOrder.Remove(mkvMergeTrackOrder.Length - 1, 1); return mkvMergeTrackOrder.ToString(); }
private static void ConvertFlacToAac(VideoFileInfo mkvFile) { foreach (TrackInfo track in mkvFile.Tracks) { if (track.Codec == flacCodecID) { Console.WriteLine("Transcoding FLAC streams {0}(id:{1}) from {2}", track.Name, track.TrackNumber, mkvFile.VideoFile.FullName); FileInfo aacFile = new FileInfo(tempFolder.FullName + Path.DirectorySeparatorChar + mkvFile.VideoFile.Name + '.' + track.MkvToolsTrackNumber + ".mp4"); String ffmpegParameters = String.Format(ffMpegBaseParameters, mkvFile.VideoFile.FullName, track.MkvToolsTrackNumber); String neroAacParameters = String.Format(neroAacEncBaseParameters, aacFile.FullName); String fullCommand = pathToFFMpeg + " " + ffmpegParameters + " | " + pathToNeroAacEnc + " " + neroAacParameters; //We pipe the stream from ffmpeg directly into the neroAAC encoder. Console.WriteLine("ffmpeg to neroAAC Command:"); Console.WriteLine(fullCommand); Process transcodeProcess = StartExternalProcess("cmd", "/C " + fullCommand); Console.WriteLine(transcodeProcess.StandardError.ReadToEnd()); transcodeProcess.WaitForExit(encodeTimeout * 1000); if (transcodeProcess.HasExited) { if (transcodeProcess.ExitCode != 0 || !aacFile.Exists) { Console.WriteLine("Error with transcoding"); } else { track.ExternalFileRef = aacFile; } } else { Console.WriteLine("MKV transcode application took longer than {0} seconds.", encodeTimeout); transcodeProcess.Kill(); } } } }
public static VideoFileInfo ParseMKVInfo(String mkvInfoFile) { FileInfo infoFile = new FileInfo(mkvInfoFile); VideoFileInfo videoInfo = new VideoFileInfo(); using (TextReader reader = infoFile.OpenText()) { String line = reader.ReadLine(); while (line != trackStart && !String.IsNullOrEmpty(line)) { if (line.StartsWith(segmentUid)) videoInfo.SegmentUID = line.Substring(segmentUid.Length); line = reader.ReadLine(); } if (line != trackStart) throw new Exception("Invalid info file format or MKV without tracks"); videoInfo.Tracks = ExtractTrackInfo(reader); } return videoInfo; }
private static void TranscodeFlac(VideoFileInfo mkvFile, DirectoryInfo targetFolder) { ConvertFlacToAac(mkvFile); RemuxFile(mkvFile, targetFolder); }
private static void RemuxFile(VideoFileInfo mkvFile, DirectoryInfo targetFolder) { FileInfo target = new FileInfo(targetFolder.FullName + Path.DirectorySeparatorChar + mkvFile.VideoFile.Name); Console.WriteLine("Remuxing {0} to {1}", mkvFile.VideoFile.FullName, target.FullName); String mkvMergeParams = PrepareMkvMergeParameters(mkvFile, target); Console.WriteLine("MkvMerge Command:"); Console.WriteLine(pathToMkvMerge + " " + mkvMergeParams); Process mkvMergeProcess = StartExternalProcess(pathToMkvMerge, mkvMergeParams); Console.WriteLine(mkvMergeProcess.StandardError.ReadToEnd()); mkvMergeProcess.WaitForExit(mergeTimeout * 1000); if (mkvMergeProcess.HasExited) { target.Refresh(); if (mkvMergeProcess.ExitCode != 0 || !target.Exists) { Console.WriteLine("Error with mkvMerge"); } else { foreach (TrackInfo track in mkvFile.Tracks) { if (track.ExternalFileRef != null && track.ExternalFileRef.Exists) track.ExternalFileRef.Delete(); } } } else { Console.WriteLine("MKV merge application took longer than {0} seconds.", mergeTimeout); mkvMergeProcess.Kill(); } }
private static String PrepareMkvMergeParameters(VideoFileInfo mkvFile, FileInfo target) { StringBuilder mkvMergeParams = new StringBuilder(); mkvMergeParams.AppendFormat("-o \"{0}\"", target.FullName); if (!String.IsNullOrWhiteSpace(mkvFile.SegmentUID)) mkvMergeParams.AppendFormat(" --segment-uid \"{0}\"", mkvFile.SegmentUID); //we keep the same segmentUID as source to preserve external chapter support. (OP/ED's etc) List<String> audioIdsToSkip = new List<String>(); foreach (TrackInfo track in mkvFile.Tracks) { if (track.TrackType == TrackType.Video) { mkvMergeParams.AppendFormat(" --compression {0}:none", track.MkvToolsTrackNumber); } if (track.TrackType == TrackType.Audio && track.Codec == flacCodecID) { audioIdsToSkip.Add(track.MkvToolsTrackNumber.ToString()); } } mkvMergeParams.AppendFormat(" --audio-tracks !{0}", String.Join(",", audioIdsToSkip)); mkvMergeParams.AppendFormat(" \"{0}\"", mkvFile.VideoFile.FullName); foreach (TrackInfo track in mkvFile.Tracks) { if (track.TrackType == TrackType.Audio && track.Codec == flacCodecID) { String reworkedTrackName = ReplaceFlacIndicator(track.Name); if(!String.IsNullOrWhiteSpace(reworkedTrackName)) mkvMergeParams.AppendFormat(" --track-name \"0:{0}\"", reworkedTrackName); if (String.IsNullOrWhiteSpace(track.Language)) //eng is the default track language, this is sometimes ommited in the source files resulting in an empty language code. mkvMergeParams.AppendFormat(" --language 0:eng"); else mkvMergeParams.AppendFormat(" --language 0:{0}", track.Language); ; mkvMergeParams.AppendFormat(" --compression 0:none"); if (!track.Default) //yes is the default value of this flag, there is no need to specify this case. mkvMergeParams.Append(" --default-track 0:no"); if(track.Forced) mkvMergeParams.Append(" --forced-track 0:yes"); //Ensure we only grab audio from this file mkvMergeParams.Append(" --no-video --no-subtitles --no-buttons --no-track-tags"); mkvMergeParams.Append(" --no-chapters --no-attachments --no-global-tags"); mkvMergeParams.AppendFormat(" --audio-tracks 0 \"{0}\"", track.ExternalFileRef.FullName); } } List<String> trackOrder = new List<String>(); Int32 externalFileCounter = 0; foreach (TrackInfo track in mkvFile.Tracks) { if (track.TrackType == TrackType.Audio && track.Codec == flacCodecID) { externalFileCounter += 1; trackOrder.Add(String.Format("{0}:0", externalFileCounter)); } else { trackOrder.Add(String.Format("0:{0}", track.MkvToolsTrackNumber)); } } mkvMergeParams.AppendFormat(" --track-order {0}", String.Join(",", trackOrder)); return mkvMergeParams.ToString(); }