public static void NormalizeAudio(String filename, StreamInfo audioStreamInfo) { if(!filename.EndsWith("ogg")) throw new Exception("Only .ogg files are currently supported for normalizing!"); double maxVolume = GetMaxVolume(filename, audioStreamInfo); double targetVolume = InstanceSettings.systemSettings.normalizeTargetVolume; String tmpFilename = InstanceSettings.temporaryFilesPath + Path.GetFileName(filename); String arguments = String.Format("-y -i \"{0}\" -af \"volume={1}dB\" -c:a libvorbis -vn \"{2}\"", filename, (-maxVolume + targetVolume).ToString(System.Globalization.CultureInfo.InvariantCulture), tmpFilename); UtilsCommon.StartProcessAndGetOutput(InstanceSettings.systemSettings.formatConvertCommand, arguments); // move new file to original position if(File.Exists(tmpFilename)) { File.Delete(filename); File.Move(tmpFilename, filename); } }
public static double GetMaxVolume(String audioFile, StreamInfo audioStreamInfo) { if(audioStreamInfo.StreamTypeValue != StreamInfo.StreamType.ST_AUDIO) throw new Exception("Tried to get volume of non-audio-stream"); String arguments = String.Format("-i \"{0}\" -map 0:{1} -af volumedetect -vn -f null /dev/null", audioFile, audioStreamInfo.StreamIndex); String stderr = UtilsCommon.StartProcessAndGetOutput(InstanceSettings.systemSettings.formatConvertCommand, arguments, true); String[] lines = stderr.Split('\n'); for(int i = lines.Length - 1; i >= 0; i--) { String line = lines[i]; if(line.Contains("max_volume")) { Match match = Regex.Match(line.Trim(), @"\[Parsed_volumedetect_0 @ (.*?)\] max_volume: (?<volume>[-.,0-9]+) dB$", RegexOptions.IgnoreCase | RegexOptions.Compiled); if(!match.Success) throw new Exception("Output of \"" + InstanceSettings.systemSettings.formatConvertCommand + "\" with filter \"volumedetect\" could not be parsed"); return Double.Parse(match.Groups["volume"].ToString(), CultureInfo.InvariantCulture); } } throw new Exception("Output of \"" + InstanceSettings.systemSettings.formatConvertCommand + "\" with filter \"volumedetect\" could not be parsed"); }
public EpisodeInfo (int index, int number, UtilsInputFiles.FileDesc videoFileDesc, UtilsInputFiles.FileDesc audioFileDesc, UtilsInputFiles.FileDesc sub1FileDesc, UtilsInputFiles.FileDesc sub2FileDesc, StreamInfo videoStreamInfo, StreamInfo audioStreamInfo, StreamInfo sub1StreamInfo, StreamInfo sub2StreamInfo) { m_index = index; m_number = number; m_videoFileDesc = videoFileDesc; m_audioFileDesc = audioFileDesc; m_subsFileDesc[0] = sub1FileDesc; m_subsFileDesc[1] = sub2FileDesc; m_videoStreamInfo = videoStreamInfo; m_audioStreamInfo = audioStreamInfo; m_subStreamInfos[0] = sub1StreamInfo; m_subStreamInfos[1] = sub2StreamInfo; }
/// <summary> /// Uses ffprobe/avprobe to query all audio, video and subtitle streams in a container file. /// </summary> public static List<StreamInfo> ReadAllStreams(String filename) { // use ffprobe/avprobe(?) to get nice XML-description of contents String stdout = UtilsCommon.StartProcessAndGetOutput(InstanceSettings.systemSettings.formatProberCommand, @"-v quiet -print_format xml -show_streams """ + filename + @""""); List<StreamInfo> allStreamInfos = new List<StreamInfo> (); StreamInfo lastStreamInfo = null; // use XmlReader to read all informations from "stream"-tags and "tag"-tags using (XmlReader reader = XmlReader.Create(new StringReader (stdout))) { while (reader.Read ()) { if (reader.NodeType != XmlNodeType.Element) continue; // the "stream"-tag contains most of the information needed as attributes if (reader.Name == "stream") { // get stream type StreamType streamType; switch(reader["codec_type"]) { case "video": streamType = StreamType.ST_VIDEO; break; case "audio": streamType = StreamType.ST_AUDIO; break; case "subtitle": streamType = StreamType.ST_SUBTITLE; break; default: streamType = StreamType.ST_UNKNOWN; break; } // read all other information into dictionary var attributeDictionary = new Dictionary<String, String>(); for(int i = 0; i < reader.AttributeCount; i++) { reader.MoveToNextAttribute(); attributeDictionary.Add(reader.Name, reader.Value); } StreamInfo streamInfo = new StreamInfo (Int32.Parse(reader["index"]), streamType, reader["codec_name"], attributeDictionary); allStreamInfos.Add (streamInfo); lastStreamInfo = streamInfo; } // the "tag"-tag provides additonal information (mainly language) if (reader.Name == "tag") { if (lastStreamInfo == null) continue; switch (reader ["key"]) { case "language": lastStreamInfo.m_language = reader ["value"] ?? ""; break; default: break; } } } } return allStreamInfos; }