/// <summary> /// Used to execute custom commands after the conversion process is compelte just before the file is moved to the desination directory /// </summary> /// <param name="prefix">Prefix for reading lines from profile</param> /// <param name="profile">Profile name</param> /// <param name="taskName">Task Name</param> /// <param name="workingPath">Temp working path</param> /// <param name="destinationPath">Destination path for converted file</param> /// <param name="convertedFile">Full path to final converted file</param> /// <param name="sourceFile">Full path to original source file</param> /// <param name="remuxFile">Full path to intermediate remuxed file</param> /// <param name="edlFile">Full path to EDL file</param> /// <param name="srtFile">Full path to SRT file</param> /// <param name="metaData">Video metadata structure for source file</param> /// <param name="jobStatus">ref to JobStatus</param> /// <param name="jobLog">JobLog</param> public CustomCommand(string prefix, string profile, string taskName, string workingPath, string destinationPath, string convertedFile, string sourceFile, string remuxFile, string edlFile, string srtFile, VideoTags metaData, JobStatus jobStatus, Log jobLog) { _profile = profile; _taskName = taskName; _jobLog = jobLog; _jobStatus = jobStatus; _workingPath = workingPath; _destinationPath = destinationPath; _convertedFile = convertedFile; _sourceFile = sourceFile; _remuxFile = remuxFile; _edlFile = edlFile; _srtFile = srtFile; _metaData = metaData; _prefix = prefix; Ini ini = new Ini(GlobalDefs.ProfileFile); commandPath = ini.ReadString(profile, prefix + "Path", "").ToLower().Trim(); commandParameters = ini.ReadString(profile, prefix + "Parameters", ""); hangPeriod = ini.ReadInteger(profile, prefix + "HangPeriod", GlobalDefs.HANG_PERIOD_DETECT); customCommandCritical = ini.ReadBoolean(profile, prefix + "Critical", false); // NOTE: if customCommandCritical is TRUE will need to return false in case it's a failure customCommandUISession = ini.ReadBoolean(profile, prefix + "UISession", false); // Does the custom command need a UI Session (Session 1) with admin privileges customCommandShowWindow = ini.ReadBoolean(profile, prefix + "ShowWindow", true); // Show the window or hide it customCommandExitCodeCheck = ini.ReadBoolean(profile, prefix + "ExitCodeCheck", false); // Don't check for exit code _jobLog.WriteEntry(this, "Custom command parameters read -> " + " \n" + _prefix + "Path = " + commandPath + " \n" + _prefix + "Parameters = " + commandParameters + " \n" + _prefix + "HangPeriod = " + hangPeriod.ToString(System.Globalization.CultureInfo.InvariantCulture) + " \n" + _prefix + "Critical = " + customCommandCritical.ToString() + " \n" + _prefix + "UISession = " + customCommandUISession.ToString() + " \n" + _prefix + "ShowWindow = " + customCommandShowWindow.ToString() + " \n" + _prefix + "ExitCodeCheck = " + customCommandExitCodeCheck.ToString(), Log.LogEntryType.Debug); }
public TiVOUserRemux(string Parameters, JobStatus jobStatus, Log jobLog, bool ignoreSuspend = false) : base(Parameters, APP_PATH, jobStatus, jobLog, ignoreSuspend) { // TODO: we need to relook at this, tivo filters still don't work in user space when launched from a service _uiAdminSessionProcess = true; // This apps needs to be run in User Space _success = false; }
private bool _encodeError = false; // Any critical error /// <summary> /// General FFMPEG to convert a file /// </summary> /// <param name="Parameters">Parameters to pass to FFMPEG</param> /// <param name="jobStatus">Reference to JobStatus</param> /// <param name="jobLog">JobLog</param> public FFmpeg(string Parameters, JobStatus jobStatus, Log jobLog, bool ignoreSuspend = false) : base(Parameters, APP_PATH, jobStatus, jobLog, ignoreSuspend) { _Parameters = " -probesize 100M -analyzeduration 300M " + _Parameters; // We need to probe deeper into the files to get the correct audio / video track information else it can lead to incorrect channel information and failure _success = false; //ffmpeg looks for a +ve output so we have a false to begin with _uiAdminSessionProcess = true; // Assume we are always using ffmpeg build with hardware API's (UI Session 1 process) }
private Collections.FixedSizeQueue<KeyValuePair<float, DateTime>> _percentageHistory = new Collections.FixedSizeQueue<KeyValuePair<float, DateTime>>(GlobalDefs.PERCENTAGE_HISTORY_SIZE); // Track last 5 % entries /// <summary> /// Default base class for starting a process within the MCEBuddy installation directory /// </summary> /// <param name="parameters">Parameters for a process</param> /// <param name="appPath">Relative path of app to MCEBuddy installation directory</param> /// <param name="ignoreSuspend">Don't stop the process if MCEBuddy is suspended by user (useful if app is being called by the GUI or can deadlock)</param> public Base(string parameters, string appPath, JobStatus jobStatus, Log jobLog, bool ignoreSuspend=false) { _ApplicationPath = Path.Combine(GlobalDefs.AppPath, appPath); _Parameters = parameters; _jobStatus = jobStatus; _jobLog = jobLog; _ignoreSuspend = ignoreSuspend; }
public FileExtractMetadata(string videoFileName, VideoTags videoTags, string tivoMAKKey, bool ignoreSuspend, JobStatus jobStatus, Log jobLog) { _videoFileName = videoFileName; _videoTags = videoTags; _jobLog = jobLog; _jobStatus = jobStatus; _tivoMAKKey = tivoMAKKey; _ignoreSuspend = ignoreSuspend; }
private string _srtFile = ""; // Subtitle file public ConvertWithFfmpeg(ConversionJobOptions conversionOptions, string tool, VideoInfo videoFile, JobStatus jobStatus, Log jobLog, Scanner commercialScan, string srtFile) : base(conversionOptions, tool, videoFile, jobStatus, jobLog, commercialScan) { passLog = Path.Combine(_workingPath, "MCEBuddy2Pass.log"); // Name of passlog file //Check if MEncoder EDL Removal has been disabled at conversion time Ini ini = new Ini(GlobalDefs.ProfileFile); if(ini.ReadBoolean(conversionOptions.profile, tool + "-SubtitleBurn", false)) _srtFile = srtFile; // Save the SRT file info otherwise skip it }
public RemuxMCERecording(ConversionJobOptions cjo, JobStatus jobStatus, Log jobLog) { _jobStatus = jobStatus; _jobLog = jobLog; _RecordingFile = cjo.sourceVideo; _destinationPath = cjo.workingPath; _requestedAudioLanguage = cjo.audioLanguage; _tivoMAKKey = cjo.tivoMAKKey; if (Util.FilePaths.CleanExt(_RecordingFile) == ".ts") // Handle TS files difference since they will have the same namess _RemuxedFile = Path.Combine(_destinationPath, Path.GetFileNameWithoutExtension(_RecordingFile) + "-REMUXED.ts"); else _RemuxedFile = Path.Combine(_destinationPath, Path.GetFileNameWithoutExtension(_RecordingFile) + ".ts"); // Read various profile parameters Ini configProfileIni = new Ini(GlobalDefs.ProfileFile); _useRemuxsupp = configProfileIni.ReadBoolean(cjo.profile, "UseWTVRemuxsupp", false); // Some videos fail with FFMPEG remuxing and Mencoder encoding (use remuxsupp for remuxing there) _jobLog.WriteEntry(this, "Force Remuxsupp (UseWTVRemuxsupp) : " + _useRemuxsupp.ToString(), Log.LogEntryType.Debug); _forceWTVStreamsRemuxing = configProfileIni.ReadBoolean(cjo.profile, "ForceWTVStreamsRemuxing", false); // Use Streams remuxing for DVRMS and WTV files _jobLog.WriteEntry(this, "Force Streams Remuxing (ForceWTVStreamsRemuxing) : " + _forceWTVStreamsRemuxing.ToString(), Log.LogEntryType.Debug); _allowH264CopyRemuxing = configProfileIni.ReadBoolean(cjo.profile, "AllowH264CopyRemuxing", true); // Allow H.264 files to be remuxed into TS without recoding to MPEG2 _jobLog.WriteEntry(this, "Allow H264 Copy Remuxing (AllowH264CopyRemuxing) (default: true) : " + _allowH264CopyRemuxing.ToString(), Log.LogEntryType.Debug); _allowAllCopyRemuxing = configProfileIni.ReadBoolean(cjo.profile, "AllowAllCopyRemuxing", false); // Allow any video codec to be remuxed into TS without recoding to MPEG2 _jobLog.WriteEntry(this, "Allow All Video codec formats Copy Remuxing (AllowAllCopyRemuxing) (default: false) : " + _allowAllCopyRemuxing.ToString(), Log.LogEntryType.Debug); // Get the media info for the recording file once for the entire operation to reuse _jobLog.WriteEntry(this, "Reading Recording file " + _RecordingFile + " media information", Log.LogEntryType.Debug); _RecordingFileMediaInfo = new FFmpegMediaInfo(_RecordingFile, _jobStatus, _jobLog); // Check for donator version of Comskip Comskip checkComskip = new Comskip(MCEBuddyConf.GlobalMCEConfig.GeneralOptions.comskipPath, _jobLog); // Check if we are using a mpeg4 video and allowing h264 video codec for commercial skipping purposes if (_allowH264CopyRemuxing) { if (_mpeg4Codecs.Any(s => s.Contains(_RecordingFileMediaInfo.MediaInfo.VideoInfo.VideoCodec.ToLower()))) { if (cjo.commercialRemoval == CommercialRemovalOptions.Comskip) { if (checkComskip.IsDonator) _jobLog.WriteEntry(this, "AllowH264CopyRemuxing will run fast for commercial detection, using donator version of Comskip", Log.LogEntryType.Information); else _jobLog.WriteEntry(this, "AllowH264CopyRemuxing is SLOW with the bundled Comskip. Use ShowAnalyzer or Comskip Donator version (http://www.comskip.org) to speed up commercial detection. Codec detected -> " + _RecordingFileMediaInfo.MediaInfo.VideoInfo.VideoCodec, Log.LogEntryType.Warning); } } } // Check if we are using an unsupported codec and copying to TS format if (_allowAllCopyRemuxing) if (!_supportedCodecs.Any(s => s.Contains(_RecordingFileMediaInfo.MediaInfo.VideoInfo.VideoCodec.ToLower()))) // Check if we using any of the default supported codecs _jobLog.WriteEntry(this, "AllowAllCopyRemuxing is enabled and an unsupported codec in the source video is detected. Some underlying programs may not work with this codec. Codec detected -> " + _RecordingFileMediaInfo.MediaInfo.VideoInfo.VideoCodec, Log.LogEntryType.Warning); }
public RemuxExt(string originalFile, string workingPath, double fps, JobStatus jobStatus, Log jobLog, string remuxTo) { _jobLog = jobLog; _jobStatus = jobStatus; _originalFile = originalFile; // By default if we aren't remuxing then the remuxed file is the original file _fps = fps; _remuxTo = remuxTo.ToLower(); _extension = FilePaths.CleanExt(originalFile); _workingPath = workingPath; _jobLog.WriteEntry(this, "Remux To : " + _remuxTo, Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Extension : " + _extension, Log.LogEntryType.Debug); }
/// <summary> /// Detects the cropping information of a video file using MEncoder. Runs automatically on initialization /// </summary> /// <param name="sourceFile">Video file to detect cropping</param> /// <param name="edlFile">EDL file to skip video sections for crop</param> public MencoderCropDetect(string sourceFile, string edlFile, JobStatus jobStatus, Log jobLog, bool ignoreSuspend = false) : base(sourceFile, APP_PATH, jobStatus, jobLog, ignoreSuspend) { // Update the parameters to be passed to mEncoder for cropdetect (ladvopts supports a max of 8 threads) _Parameters = Util.FilePaths.FixSpaces(sourceFile) + " -lavdopts threads=" + Math.Min(8, Environment.ProcessorCount).ToString(System.Globalization.CultureInfo.InvariantCulture) + " -nosound -ovc raw -o nul -vf cropdetect"; // setup for multiple processors to speed it up if (!string.IsNullOrEmpty(edlFile)) _Parameters += " -edl " + Util.FilePaths.FixSpaces(edlFile); // If there is an EDL file use it to speed things up _success = true; //by deafult everything here works unless the process hangs Run(); // Run it now }
/// <summary> /// Extract the metadata from the video file (WTV/DVRMS/MP4/MKV/AVI/TS XML) and supplement with information downloaded from TVDB and MovieDB /// </summary> /// <param name="cjo">Conversion job options</param> /// <param name="disableDownloadSeriesDetails">(Optional) True if you want to override adn disable the DownloadSeriesDetails option from TVDB/MovieDB</param> public VideoMetaData(ConversionJobOptions cjo, JobStatus jobStatus, Log jobLog, bool disableDownloadSeriesDetails = false) { _videoFileName = cjo.sourceVideo; _downloadSeriesDetails = (cjo.downloadSeriesDetails && !disableDownloadSeriesDetails); // special case, if want to override it _downloadBannerFile = (cjo.downloadBanner && !disableDownloadSeriesDetails); _jobStatus = jobStatus; _jobLog = jobLog; _metadataCorrections = cjo.metadataCorrections; _tivoMAKKey = cjo.tivoMAKKey; _profile = cjo.profile; _taskName = cjo.taskName; _forceShowType = cjo.forceShowType; _prioritizeMatchDate = cjo.prioritizeOriginalBroadcastDateMatch; }
public Scanner(ConversionJobOptions conversionOptions, string videoFileName, bool useShowAnalyzer, float duration, JobStatus jobStatus, Log jobLog) : base(conversionOptions.profile, videoFileName, duration, "", 0, jobStatus, jobLog) { _videoFileName = videoFileName; _useShowAnalyzer = useShowAnalyzer; _jobStatus = jobStatus; _jobLog = jobLog; _profile = conversionOptions.profile; _convOptions = conversionOptions; _customComskipPath = MCEBuddyConf.GlobalMCEConfig.GeneralOptions.comskipPath; if (!String.IsNullOrWhiteSpace(_customComskipPath)) _jobLog.WriteEntry(this, "Using Custom Comskip Path -> " + MCEBuddyConf.GlobalMCEConfig.GeneralOptions.comskipPath, Log.LogEntryType.Information); }
private const double DRC = 0.8; // Dynamic Range Compression to 80% public ConvertWithMencoder(ConversionJobOptions conversionOptions, string tool, VideoInfo videoFile, JobStatus jobStatus, Log jobLog, Scanner commercialScan) : base(conversionOptions, tool, videoFile, jobStatus, jobLog, commercialScan) { //Check if MEncoder EDL Removal has been disabled at conversion time Ini ini = new Ini(GlobalDefs.ProfileFile); mEncoderEDLSkip = ini.ReadBoolean(conversionOptions.profile, "MEncoderEDLSkip", false); _extractCC = conversionOptions.extractCC; if (!String.IsNullOrEmpty(_extractCC)) // If Closed Caption extraction is enabled, we don't use cut EDL using Mencoder during encoding, Mencoder has a bug which causes it to cut out of sync with the EDL file which throws the CC out of sync, it will be cut separately { _jobLog.WriteEntry(this, Localise.GetPhrase("Closed Captions Enabled, skipping EDL cutting during encoding"), Log.LogEntryType.Information); mEncoderEDLSkip = true; } if ((_startTrim != 0) || (_endTrim != 0)) // If trimming is enabled skip cutting using EDL otherwise MEncoder messes it up { _jobLog.WriteEntry(this, Localise.GetPhrase("Trimming Enabled, skipping EDL cutting during encoding"), Log.LogEntryType.Information); mEncoderEDLSkip = true; } }
private string _XMLCHAPFile = ""; // If the XML CHAP file exists /// <summary> /// Class for manipulating EDL, EDLP and CHAP files /// </summary> /// <param name="profile">Conversion Profile name</param> /// <param name="fileName">Full path Video from which EDL, EDLP and CHAP filenames will be dervied</param> /// <param name="duration">Length of video</param> /// <param name="edlFile">EDL File used to set the initial EDLFile property</param> /// <param name="initialSkipSeconds">Number of seconds of the file cut which needs to be adjusted while calculating cut segments</param> public EDL(string profile, string fileName, float duration, string edlFile, float initialSkipSeconds, JobStatus jobStatus, Log jobLog) { _profile = profile; _videoFileName = fileName; _duration = duration; _initialSkipSeconds = initialSkipSeconds; _jobLog = jobLog; _jobStatus = jobStatus; _EDLFile = edlFile; //check if we need to use the EDL file instead of the EDLP file Ini ini = new Ini(GlobalDefs.ProfileFile); _forceEDL = ini.ReadBoolean(_profile, "ForceEDL", false); _forceEDLP = ini.ReadBoolean(_profile, "ForceEDLP", false); // Fix duration for initial skip seconds _duration = (_duration - _initialSkipSeconds < 0 ? 0 : _duration - _initialSkipSeconds); _jobLog.WriteEntry(this, "EDL: Initial skip seconds adjustment " + _initialSkipSeconds.ToString(CultureInfo.InvariantCulture) + " seconds.", Log.LogEntryType.Debug); }
public Remover(string profile, string uncutVideo, string workingPath, string edlFile, float initialSkipSeconds, VideoInfo remuxedVideoFileInfo, JobStatus jobStatus, Log jobLog) : base(profile, uncutVideo, remuxedVideoFileInfo.Duration, edlFile, initialSkipSeconds, jobStatus, jobLog) { _remuxedVideoFileInfo = remuxedVideoFileInfo; _uncutVideo = uncutVideo; _ext = Util.FilePaths.CleanExt(_uncutVideo); _workingPath = workingPath; _duration = _remuxedVideoFileInfo.Duration; _jobStatus = jobStatus; _jobLog = jobLog; // Read various profile parameters Ini configProfileIni = new Ini(GlobalDefs.ProfileFile); _cutMP4Alternative = configProfileIni.ReadBoolean(profile, "CutMP4Alternate", false); // for FFMPEG and Handbrake, we have commerical cutting options, for mEncoder cutting is done during conversion using -edl option jobLog.WriteEntry("MP4 Alternative Cutting -> " + _cutMP4Alternative.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Debug); _universalCommercialRemover = configProfileIni.ReadBoolean(profile, "UniversalCommercialRemover", false); // Forcing the use of CutFFMPEG which works on all video types jobLog.WriteEntry("Universal Commercial Remover -> " + _universalCommercialRemover.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Debug); string commercialMerge = configProfileIni.ReadString(profile, "CommercialMergeTool", ""); // Force tool to merge commercial segments jobLog.WriteEntry("Force Commercial Segment Merging Tool -> " + commercialMerge, Log.LogEntryType.Debug); switch (commercialMerge.ToLower()) { case "avidemux": _useAVIDemuxMerge = true; break; case "ffmpeg": _useFFMPEGMerge = true; break; case "": break; default: jobLog.WriteEntry("INVALID Force Commercial Segment Merging Tool -> " + commercialMerge, Log.LogEntryType.Warning); break; } }
public ConvertWithHandbrake(ConversionJobOptions conversionOptions, string tool, VideoInfo videoFile, JobStatus jobStatus, Log jobLog, Scanner commercialScan) : base(conversionOptions, tool, videoFile, jobStatus, jobLog, commercialScan) { // Check if we have hardware encoding support available on the system Handbrake hb = new Handbrake(jobLog); hardwareEncodingAvailable = hb.QuickSyncEncodingAvailable; //Check if the profiles is setup for Hardware encoding, if so don't adjust hardware encoding options Ini ini = new Ini(GlobalDefs.ProfileFile); bool profileHardwareEncoding = ini.ReadBoolean(conversionOptions.profile, tool + "-UsingHardwareEncoding", false); if (_preferHardwareEncoding && profileHardwareEncoding) { _jobLog.WriteEntry(this, "Hardware enabled handbrake profile, disabling auto hardware encoder adjustments", Log.LogEntryType.Debug); _preferHardwareEncoding = false; // Don't change any settings, this profile is already setup for hardware encoding } // Check if we are using any of the h264 codecs, only then can we use hardware encoder for H264 if (_preferHardwareEncoding && !h264Encoders.Any((new FFMpegMEncoderParams(_videoParams)).ParameterValue("-e").ToLower().Equals)) { _jobLog.WriteEntry(this, "Cannot find h264 encoder, disabling auto hardware h264 encoder adjustments", Log.LogEntryType.Debug); _preferHardwareEncoding = false; // Don't use hardware encoder since this isn't a h264 profile } }
public ConversionJob(ConversionJobOptions conversionJobOptions, VideoMetaData metaData) { _conversionOptions = conversionJobOptions; // First thing to do _metaData = metaData; // Save the metadata if present _originalFileNameBackup = _conversionOptions.sourceVideo; // This is what we use to report to the world what we're working on, _sourceVideo may change under certain conditions below if (String.IsNullOrEmpty(_conversionOptions.destinationPath)) _conversionOptions.destinationPath = Path.GetDirectoryName(_conversionOptions.sourceVideo); // No dest path = convert in place _jobStatus = new JobStatus(); _jobStatus.SourceFile = _conversionOptions.sourceVideo; _jobStatus.TaskName = _conversionOptions.taskName; // Read various engine parameters _maxConcurrentJobs = MCEBuddyConf.GlobalMCEConfig.GeneralOptions.maxConcurrentJobs; _spaceCheck = MCEBuddyConf.GlobalMCEConfig.GeneralOptions.spaceCheck; _subtitleSegmentOffset = MCEBuddyConf.GlobalMCEConfig.GeneralOptions.subtitleSegmentOffset; // Read various profile parameters Ini configProfileIni = new Ini(GlobalDefs.ProfileFile); // Profile only parameters _preConversionCommercialRemover = configProfileIni.ReadBoolean(_conversionOptions.profile, "PreConversionCommercialRemover", false); // Check if the user wants to remove commercials before the actual conversion in which case we always return false - i.e. remove commercial during remux stage _copyLOGFile = configProfileIni.ReadBoolean(_conversionOptions.profile, "CopyLogFile", false); // Check if the user wants to save the log file generated by Comskip _copyPropertiesFile = configProfileIni.ReadBoolean(_conversionOptions.profile, "CopyPropertiesFile", false); // Check if the user wants to save the properties file for SageTV metadata if (configProfileIni.ReadString(_conversionOptions.profile, "AutoDeinterlace", "default") == "default") _autoDeinterlace = _conversionOptions.autoDeInterlace; else _autoDeinterlace = configProfileIni.ReadBoolean(_conversionOptions.profile, "AutoDeinterlace", false); if (_conversionOptions.renameOnly) _commercialSkipCut = true; //no cutting if we are renaming only else if (configProfileIni.ReadString(_conversionOptions.profile, "CommercialSkipCut", "default") == "default") _commercialSkipCut = _conversionOptions.commercialSkipCut; else _commercialSkipCut = configProfileIni.ReadBoolean(_conversionOptions.profile, "CommercialSkipCut", false); }
/// <summary> /// Special function to run Scan Type detection using the IDET video filter. /// By default, this will skip 300 seconds into the video and then analyze it for 120 seconds to collect data about the field frames. /// You can override the default <paramref name="skipSeconds"/> and <paramref name="analyzeSeconds"/> by putting non 0 values in the respective parameters. /// The results are stored in the MFInterlaceDetectionResults (Multi Frame MORE reliable) and SFInterlaceDetectionResults (Single Frame). /// When this mode is active, ONLY interlace detection is done, the rest of the MediaInfo is NOT available (null) /// Run automatically on initialization /// </summary> /// <param name="skipSeconds">Number of seconds of the initial video to skip before starting interlace detection (0 for default)</param> /// <param name="analyzeSeconds">Number of seconds of the video to analyze for interlace detection (0 for default)</param> public FFmpegMediaInfo(string fileName, JobStatus jobStatus, Log jobLog, ulong skipSeconds, ulong analyzeSeconds, bool ignoreSuspend = false) : base(fileName, FFMPEG_APP_PATH, jobStatus, jobLog, ignoreSuspend) { mediaInfo = null; // In this mode, there is no media info idetMode = true; // We are running a special mode useFFProbe = false; // We are using FFMPEG here not FFProbe parseError = true; // In this mode parse error is default until we find what we need _success = true; // information always suceeds unless we find an error in the output // Check for custom overrides if (skipSeconds > 0) IDET_SKIP_SECONDS = skipSeconds; if (analyzeSeconds > 0) IDET_ANALYZE_SECONDS = analyzeSeconds; // -probesize 100M -analyzeduration 300M are important to identify broken audio streams in some files _Parameters = " -probesize 100M -analyzeduration 300M -y -ss " + IDET_SKIP_SECONDS.ToString(CultureInfo.InvariantCulture) + " -i " + Util.FilePaths.FixSpaces(fileName) + " -vf idet -an -sn -t " + IDET_ANALYZE_SECONDS.ToString(CultureInfo.InvariantCulture) + " -f rawvideo NUL"; // create the format for run the command Run(); }
/// <summary> /// Gets information about the video file and stores it. /// The ParseError flag is set if there is an error trying to parse the video information, in which the information available in not reliable. /// Run automatically on initialization /// </summary> /// <param name="ignoreSuspend">Set this if you want to ignore the suspend/pause command, typically used when this function is called from a GUI to prevent a deadlock/hang</param> public FFmpegMediaInfo(string fileName, JobStatus jobStatus, Log jobLog, bool ignoreSuspend = false) : base(fileName, FFPROBE_APP_PATH, jobStatus, jobLog, ignoreSuspend) { // Check if FFProbe exists, if not then fallback to FFMpeg if (useFFProbe && !File.Exists(_ApplicationPath)) { jobLog.WriteEntry(this, "FFProbe not found, switching to FFMpeg", Log.LogEntryType.Warning); _ApplicationPath = Path.Combine(GlobalDefs.AppPath, FFMPEG_APP_PATH); useFFProbe = false; } mediaInfo = new MediaInfo(); mediaInfo.VideoInfo = new MediaInfo.Video(); // We have only 1 video track per file, audio/subtitle tracks are created and added as detected _success = true; // information always suceeds unless we find an error in the output // -probesize 100M -analyzeduration 300M are important to identify broken audio streams in some files // TODO: FFPROBE -> For now we only process independent streams and ignore streams embedded within programs (-show_programs). This is because streams embedded within programs do not have unique stream ID's and PID's (they repeat within each program). How does MCEBuddy handle mpegts_service_id (programs)? if (useFFProbe) // FFPROBE _Parameters = " -probesize 100M -analyzeduration 300M -v quiet -print_format json -show_format -show_streams -i " + Util.FilePaths.FixSpaces(fileName); // FFPROBE create the format for run the command else // FFMPEG _Parameters = " -probesize 100M -analyzeduration 300M -i " + Util.FilePaths.FixSpaces(fileName); // FFMPEG create the format for run the command Run(); }
/// <summary> /// Dumps all media information about file into the log using either FFProbe or FFMPEG, does NOT analyze, parse or store the information /// </summary> /// <param name="fileName">Filename to dump information about</param> public static void DumpFileInformation(string fileName, JobStatus jobStatus, Log jobLog) { jobLog.WriteEntry("Dumping complete information about the file " + fileName, Log.LogEntryType.Debug); // Check if FFProbe exists, if not then fallback to FFMpeg string applicationPath = FFPROBE_APP_PATH; if (!File.Exists(Path.Combine(GlobalDefs.AppPath, FFPROBE_APP_PATH))) { jobLog.WriteEntry("FFProbe not found, switching to FFMpeg", Log.LogEntryType.Warning); applicationPath = FFMPEG_APP_PATH; } // -probesize 100M -analyzeduration 300M are important to identify broken audio streams in some files string parameters = " -probesize 100M -analyzeduration 300M -i " + Util.FilePaths.FixSpaces(fileName); // FFMPEG create the format for run the command Base mediaInfo = new Base(parameters, applicationPath, jobStatus, jobLog); mediaInfo.Run(); // Dump it }
/// <summary> /// FFMPEG to convert a DVRMS file /// </summary> /// <param name="Parameters">Parameters to pass to FFMPEG</param> /// <param name="DVRMS">Set to true if converting a DVRMS file</param> /// <param name="jobStatus">Reference to JobStatus</param> /// <param name="jobLog">JobLog</param> public FFmpeg(string Parameters, bool DVRMS, JobStatus jobStatus, Log jobLog, bool ignoreSuspend = false) : base(Parameters, DVRMS_APP_PATH, jobStatus, jobLog, ignoreSuspend) { _success = false; //ffmpeg looks for a +ve output so we have a false to begin with }
/// <summary> /// Generic function to run a FFMPEG command handle common errors related to FFMPEG conversion /// </summary> /// <param name="cmdParams">Command parameters to pass to ffmpeg</param> /// <param name="outputFile">Exact name of the output file as it appears in the command paramters (including quotes if required)</param> /// <param name="checkZeroOutputFileSize">If true, will check output file size and function will return false if the size is 0 or file doesn't exist, false to ignore output filesize and presence</param> /// <param name="ffmpegExecutedObject">Returns a pointer to the final executed ffmpeg object</param> /// <returns>True if successful</returns> public static bool FFMpegExecuteAndHandleErrors(string cmdParams, JobStatus jobStatus, Log jobLog, string outputFile, bool checkZeroOutputFileSize, out FFmpeg ffmpegExecutedObject) { FFmpeg ffmpeg = new FFmpeg(cmdParams, jobStatus, jobLog); ffmpeg.Run(); // Check if it's a h264_mp4toannexb error, when converting H.264 video to MPEGTS format this can sometimes be an issue if (!ffmpeg.Success && ffmpeg.H264MP4ToAnnexBError) { jobLog.WriteEntry("h264_mp4toannexb error, retying and setting bitstream flag", Log.LogEntryType.Warning); // -bsf h264_mp4toannexb is required when this error occurs, put it just before the output filename cmdParams = cmdParams.Insert(cmdParams.IndexOf(outputFile), "-bsf h264_mp4toannexb "); ffmpeg = new FFmpeg(cmdParams, jobStatus, jobLog); ffmpeg.Run(); } // Check if it's a aac_adtstoasc error, when converting AAC Audio from MPEGTS to MP4 format this can sometimes be an issue if (!ffmpeg.Success && ffmpeg.AACADTSToASCError) { jobLog.WriteEntry("aac_adtstoasc error, retying and setting bitstream flag", Log.LogEntryType.Warning); // -bsf aac_adtstoasc is required when this error occurs, put it just before the output filename cmdParams = cmdParams.Insert(cmdParams.IndexOf(outputFile), "-bsf:a aac_adtstoasc "); ffmpeg = new FFmpeg(cmdParams, jobStatus, jobLog); ffmpeg.Run(); } // Check if we are asked to check for output filesize only here (generic errors) // Otherwise it might an error related to genpts (check if we ran the previous ffmpeg related to h264_mp4toannexb and it succeded) - genpts is done after trying to fix other issues if (checkZeroOutputFileSize) jobLog.WriteEntry("Checking output file size [KB] -> " + (Util.FileIO.FileSize(outputFile) / 1024).ToString("N", System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); if ((!ffmpeg.Success || (checkZeroOutputFileSize ? (FileIO.FileSize(outputFile) <= 0) : false)) && !cmdParams.Contains("genpts")) // Possible that some combinations used prior to calling this already have genpts in the command line { jobLog.WriteEntry("Ffmpeg conversion failed, retying using GenPts", Log.LogEntryType.Warning); // genpt is required sometimes when -ss is specified before the inputs file, see ffmpeg ticket #2054 cmdParams = "-fflags +genpts " + cmdParams; ffmpeg = new FFmpeg(cmdParams, jobStatus, jobLog); ffmpeg.Run(); } // Check again post genpts if it's a h264_mp4toannexb error (if not already done), when converting H.264 video to MPEGTS format this can sometimes be an issue if (!ffmpeg.Success && ffmpeg.H264MP4ToAnnexBError && !cmdParams.Contains("h264_mp4toannexb")) { jobLog.WriteEntry("H264MP4ToAnnexBError error, retying and setting bitstream flag", Log.LogEntryType.Warning); // -bsf h264_mp4toannexb is required when this error occurs, put it just before the output filename cmdParams = cmdParams.Insert(cmdParams.IndexOf(outputFile), "-bsf h264_mp4toannexb "); ffmpeg = new FFmpeg(cmdParams, jobStatus, jobLog); ffmpeg.Run(); } // Check again post genpts if it's a aac_adtstoasc error (if not already done), when converting AAC Audio from MPEGTS to MP4 format this can sometimes be an issue if (!ffmpeg.Success && ffmpeg.AACADTSToASCError && !cmdParams.Contains("aac_adtstoasc")) { jobLog.WriteEntry("aac_adtstoasc error, retying and setting bitstream flag", Log.LogEntryType.Warning); // -bsf aac_adtstoasc is required when this error occurs, put it just before the output filename cmdParams = cmdParams.Insert(cmdParams.IndexOf(outputFile), "-bsf:a aac_adtstoasc "); ffmpeg = new FFmpeg(cmdParams, jobStatus, jobLog); ffmpeg.Run(); } ffmpegExecutedObject = ffmpeg; // Set the return object to the final run ffmpeg object jobLog.WriteEntry("FFMpeg output file size [KB] -> " + (Util.FileIO.FileSize(outputFile) / 1024).ToString("N", System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); return (ffmpeg.Success && (checkZeroOutputFileSize ? (FileIO.FileSize(outputFile) > 0) : true)); }
/// <summary> /// Generic function to run a FFMPEG command handle common errors related to FFMPEG conversion /// </summary> /// <param name="cmdParams">Command parameters to pass to ffmpeg</param> /// <param name="outputFile">Exact name of the output file as it appears in the command paramters (including quotes if required)</param> /// <param name="checkZeroOutputFileSize">If true, will check output file size and function will return false if the size is 0 or file doesn't exist, false to ignore output filesize and presence</param> /// <returns>True if successful</returns> public static bool FFMpegExecuteAndHandleErrors(string cmdParams, JobStatus jobStatus, Log jobLog, string outputFile, bool checkZeroOutputFileSize) { FFmpeg retFFMpeg; // Dummy return FFMpegExecuteAndHandleErrors(cmdParams, jobStatus, jobLog, outputFile, checkZeroOutputFileSize, out retFFMpeg); }
/// <summary> /// Generic function to run a FFMPEG command handle common errors related to FFMPEG conversion /// </summary> /// <param name="cmdParams">Command parameters to pass to ffmpeg</param> /// <param name="outputFile">Exact name of the output file as it appears in the command paramters (including quotes if required)</param> /// <returns>True if successful</returns> public static bool FFMpegExecuteAndHandleErrors(string cmdParams, JobStatus jobStatus, Log jobLog, string outputFile) { return FFMpegExecuteAndHandleErrors(cmdParams, jobStatus, jobLog, outputFile, true); }
public RemuxSupp(string Parameters, JobStatus jobStatus, Log jobLog, bool ignoreSuspend = false) : base(Parameters, APP_PATH, jobStatus, jobLog, ignoreSuspend) { _success = true; //ReMuxSupp looks for an error in it's handlers so by default we are true }
public AVIDemux(string Parameters, JobStatus jobStatus, Log jobLog, bool ignoreSuspend = false) : base(Parameters, APP_PATH, jobStatus, jobLog, ignoreSuspend) { _success = true; }
public ConvertWithCopy(ConversionJobOptions conversionOptions, string tool, VideoInfo videoFile, JobStatus jobStatus, Log jobLog, Scanner commercialScan) : base(conversionOptions, tool, videoFile, jobStatus, jobLog, commercialScan) { }
public CCExtractor(string Parameters, JobStatus jobStatus, Log jobLog, bool ignoreSuspend = false) : base(Parameters, APP_PATH, jobStatus, jobLog, ignoreSuspend) { _success = false; //CCExtractor looks for success criteria }
/// <summary> /// Base class for starting a custom process with custom parameters and absolute path /// </summary> /// <param name="showWindow">If false then the window for the custom app is hidden</param> /// <param name="parameters">Parameters for the custom process</param> /// <param name="appPath">Absolute Path to custom process</param> /// <param name="uiAdminSession">True if the app needs to run in UI Session 1</param> /// <param name="ignoreSuspend">Don't stop the process if MCEBuddy is suspended by user (useful if app is being called by the GUI or can deadlock)</param> public Base(bool showWindow, string parameters, string appPath, bool uiAdminSession, JobStatus jobStatus, Log jobLog, bool ignoreSuspend = false) { _showWindow = showWindow; // Do we need to hide the window? _ApplicationPath = appPath; // Absolute path _Parameters = parameters; _jobStatus = jobStatus; _jobLog = jobLog; _uiAdminSessionProcess = uiAdminSession; _ignoreSuspend = ignoreSuspend; // Set the default, it can be overriden later _success = true; // by default for custom apps, there is no output handler to assume success is true }
private string _renameConvertedFileWithOriginalName = ""; // Keep track incase of filename conflict protected ConvertBase(ConversionJobOptions conversionOptions, string tool, VideoInfo videoFile, JobStatus jobStatus, Log jobLog, Scanner commercialScan) : base (true) { //Setup log and status _jobStatus = jobStatus; _jobLog = jobLog; //Set the destination paths _workingPath = conversionOptions.workingPath; Util.FilePaths.CreateDir(_workingPath); // Check first up to see if the source video uses an unsupported combination for this profile // Container, Video Codec, Audio Codec and whether it was originally a Media Center recording or not _videoFile = videoFile; _commercialScan = commercialScan; if (CheckUnsupported(conversionOptions.profile, tool)) return; // Set the input params and get the standard settings _maxWidth = conversionOptions.maxWidth; _userQuality = conversionOptions.qualityMultiplier; _volume = conversionOptions.volumeMultiplier; _drc = conversionOptions.drc; _startTrim = conversionOptions.startTrim; _endTrim = conversionOptions.endTrim; _encoderChooseBestAudioTrack = conversionOptions.encoderSelectBestAudioTrack; _fps = conversionOptions.FPS; _preferHardwareEncoding = conversionOptions.preferHardwareEncoding; Ini ini = new Ini(GlobalDefs.ProfileFile); // Profile override parameters - if default (i.e. does not exist then use conversion options else use profile parameters) if (ini.ReadString(conversionOptions.profile, "2ChannelAudio", "default") == "default") _2ChannelAudio = conversionOptions.stereoAudio; else _2ChannelAudio = ini.ReadBoolean(conversionOptions.profile, "2ChannelAudio", false); // Fix output to 2 channels (from profile) if (ini.ReadString(conversionOptions.profile, "SkipCropping", "default") == "default") _skipCropping = conversionOptions.disableCropping; else _skipCropping = ini.ReadBoolean(conversionOptions.profile, "SkipCropping", false); // Cropping can be forced in the profile if (ini.ReadString(conversionOptions.profile, "AutoDeinterlace", "default") == "default") _autoDeInterlacing = conversionOptions.autoDeInterlace; else _autoDeInterlacing = ini.ReadBoolean(conversionOptions.profile, "AutoDeinterlace", false); if (conversionOptions.renameOnly) _commercialSkipCut = true; //no cutting if we are renaming only else if (ini.ReadString(conversionOptions.profile, "CommercialSkipCut", "default") == "default") _commercialSkipCut = conversionOptions.commercialSkipCut; else _commercialSkipCut = ini.ReadBoolean(conversionOptions.profile, "CommercialSkipCut", false); // Profile only parameters _fixedResolution = ini.ReadBoolean(conversionOptions.profile, "FixedResolution", false); _2Pass = ini.ReadBoolean(conversionOptions.profile, "2pass", false); _generalParams = ini.ReadString(conversionOptions.profile, tool + "-general", ""); _videoParams = ini.ReadString(conversionOptions.profile, tool + "-video", ""); _audioParams = ini.ReadString(conversionOptions.profile, tool + "-audio", ""); _extension = _videoFile.Extension = ini.ReadString(conversionOptions.profile, tool + "-ext", "").ToLower().Trim(); if (string.IsNullOrWhiteSpace(_extension)) // Special case copy converter if there is no specified extension, it will be using the source file extension _extension = FilePaths.CleanExt(SourceVideo); _remuxTo = _videoFile.RemuxTo = ini.ReadString(conversionOptions.profile, tool + "-remuxto", "").ToLower().Trim(); _audioDelay = ini.ReadString(conversionOptions.profile, tool + "-audiodelay", "skip").ToLower().Trim(); if (_audioDelay == "auto") // Use the audio delay specified in the file _toolAudioDelay = videoFile.AudioDelay; else if (_audioDelay != "skip") double.TryParse(_audioDelay, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out _toolAudioDelay); if (conversionOptions.audioOffset != 0) // Conversion options Audio Delay takes priority over profile Audio Delay _toolAudioDelay = conversionOptions.audioOffset; // Audio select the AC3 audio option if the source video has AC3) if (((videoFile.AudioCodec == "ac-3") || (videoFile.AudioCodec == "ac3") || (videoFile.AudioCodec != "e-ac-3") || (videoFile.AudioCodec != "eac3")) && (ini.ReadString(conversionOptions.profile, tool + "-audioac3", "") != "")) _audioParams = ini.ReadString(conversionOptions.profile, tool + "-audioac3", _audioParams); // E-AC3 test option if the source video has E-AC3 - Not required as mencoder can handle eac3 audio /* if (videoFile.AudioCodec == "e-ac-3" || _videoFile.AudioCodec != "eac3") { _audioParams = ini.ReadString(conversionOptions.profile, tool + "-audioeac3", _audioParams); if ((_audioParams == "") && (tool == "mencoder")) _audioParams = "-noaudio "; }*/ // Important to use temp name while converting - sometimes the sources files are copied to the working directory and the converted files conflict with teh original filename, compensate. E.g. TS file input, TS file output with Copy converter _convertedFile = Path.Combine(_workingPath, Path.GetFileNameWithoutExtension(SourceVideo) + "-converted" + _extension); _renameConvertedFileWithOriginalName = Path.Combine(_workingPath, Path.GetFileNameWithoutExtension(SourceVideo) + _extension); }
public TrimVideo(string profile, JobStatus jobStatus, Log jobLog) { _profile = profile; _jobLog = jobLog; _jobStatus = jobStatus; }