public bool Convert() // THE MAIN CONVERSION ROUTINE { if (_unsupported) return false; _jobLog.WriteEntry(this, "Main conversion routine DEBUG", Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Source Video File : " + _videoFile.SourceVideo, Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Extension : " + _extension, Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Remux To : " + _remuxTo, Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Auto Enable Hardware Encoding : " + _preferHardwareEncoding.ToString(), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "2 Pass : "******"Fixed Resolution : " + _fixedResolution.ToString(), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Skip Cropping (profile + conversion option) : " + _skipCropping.ToString(), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Video Audio Delay : " + _videoFile.AudioDelay.ToString(System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Manual Audio Delay : " + _toolAudioDelay.ToString(System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Skip Audio Delay : " + _audioDelay, Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Max Width : " + _maxWidth.ToString(), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "User Quality : " + _userQuality.ToString(System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Audio Track : " + _videoFile.AudioTrack.ToString(System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Start Trim : " + _startTrim.ToString(), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Stop Trim : " + _endTrim.ToString(), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Output FPS : " + _fps, Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Auto DeInterlacing (profile + conversion option): " + _autoDeInterlacing.ToString(), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Working Path : " + _workingPath, Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Temp Converted File : " + _convertedFile, Log.LogEntryType.Debug); _jobLog.WriteEntry(this, "Final Converted File : " + _renameConvertedFileWithOriginalName, Log.LogEntryType.Debug); _jobLog.WriteEntry(this, ("Source video file, file size [KB]") + " " + (FileIO.FileSize(SourceVideo) / 1024).ToString("N", System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); // WAY TO BUILD THE COMMAND LINE // GeneralParameters + InputFile + VideoOptions + AudioOptions + OutputFile // GENERAL PARAMETERS _jobLog.WriteEntry(this, ("Setting up General conversion parameters :") + " " + _generalParams, Log.LogEntryType.Information); AppendParameters(_generalParams); // General Parameters // Set the DRC before the input file for some encoders like ffmpeg if (_drc) { if ((_videoFile.AudioCodec == "ac-3") || (_videoFile.AudioCodec == "ac3") || (_videoFile.AudioCodec != "e-ac-3") || (_videoFile.AudioCodec != "eac3")) // DRC only applies to AC3 audio { _jobLog.WriteEntry(this, ("Setting up PreDRC"), Log.LogEntryType.Information); if (_audioParams.ToLower().Contains("copy")) _jobLog.WriteEntry(this, ("Copy Audio stream detected, skipping DRC settings"), Log.LogEntryType.Warning); else SetAudioPreDRC(); // do this before we BEFORE setting the input filename } else _jobLog.WriteEntry(this, ("Non AC3 Source Audio, DRC not applicable"), Log.LogEntryType.Information); } // INPUT FILE _jobLog.WriteEntry(this, ("Setting up input file name parameters"), Log.LogEntryType.Information); SetInputFileName(); // Input Filename // VIDEO PARAMETERS _jobLog.WriteEntry(this, ("Setting up video conversion parameters :") + " " + _videoParams, Log.LogEntryType.Information); AppendParameters(_videoParams); // Video Parameters // Get the value of the preset width before we start modifying _isPresetVideoWidth = IsPresetVideoWidth(); _jobLog.WriteEntry(this, "Is preset video size -> " + _isPresetVideoWidth.ToString(), Log.LogEntryType.Information); // Set the start and end trim parameters (after the video parameters) if trimming is not already done if ((_startTrim != 0) || (_endTrim != 0)) { bool trimFile = false; _jobLog.WriteEntry(this, "Setting up trim parameters", Log.LogEntryType.Information); //Sanity checking if we need to trim if (_startTrim != 0) { if (_startTrim < _videoFile.Duration) trimFile = true; else { _jobLog.WriteEntry(this, "Start trim (" + _startTrim.ToString() + ") greater than file duration (" + _videoFile.Duration.ToString(System.Globalization.CultureInfo.InvariantCulture) + "). Skipping start trimming.", Log.LogEntryType.Warning); _startTrim = 0; } } if (_endTrim != 0) { int encDuration = (((int)_videoFile.Duration) - _endTrim) - (_startTrim); // by default _startTrim is 0 if (encDuration > 0) trimFile = true; else { _jobLog.WriteEntry(this, "End trim (" + _endTrim.ToString() + ") + Start trim (" + _startTrim.ToString() + ") greater than file duration (" + _videoFile.Duration.ToString(System.Globalization.CultureInfo.InvariantCulture) + "). Skipping end trimming.", Log.LogEntryType.Warning); _endTrim = 0; } } if (trimFile) SetVideoTrim(); // Set Trim Parameters else _jobLog.WriteEntry(this, "Start trim and end trim skipped. Skipping trimming.", Log.LogEntryType.Warning); } // Set the interlacing filters as the first filter in the chain, before processing anything SetVideoDeInterlacing(); // Set the pre cropping BEFORE scaling, filter chain rule _jobLog.WriteEntry(this, "Setting up crop parameters", Log.LogEntryType.Information); SetVideoCropping(); //Set the scaling if (!_fixedResolution && !_isPresetVideoWidth) { int VideoWidth = _videoFile.Width; _jobLog.WriteEntry(this, ("Checking if video resizing required"), Log.LogEntryType.Information); if ((_videoFile.CropWidth > 0) && (_videoFile.CropWidth < _videoFile.Width)) { VideoWidth = _videoFile.CropWidth; } // If we do not need to scale, don't if (VideoWidth > _maxWidth) { _jobLog.WriteEntry(this, ("Setting up video resize parameters"), Log.LogEntryType.Information); SetVideoResize(); // Set Resize parameters } } else _jobLog.WriteEntry(this, ("Fixed resolution video, no resizing"), Log.LogEntryType.Information); // Sometimes we need to set the Aspect Ratio as the last parameter in the video filter chain (e.g. with libxvid) _jobLog.WriteEntry(this, ("Setting up aspect ratio if required"), Log.LogEntryType.Information); SetVideoAspectRatio(); // Adjust the bitrate to compensate for resizing and cropping _jobLog.WriteEntry(this, ("Setting up bitrate and quality parameters"), Log.LogEntryType.Information); AdjustResizeCropBitrateQuality(); if (_userQuality <= 0.1) _userQuality = 0.1; // If we using quality instead of bitrate if (ConstantVideoQuality && (_userQuality > 2)) _userQuality = 2; // Update the BitRate/Quality parameters SetVideoBitrateAndQuality(); // Set the output framerate if required SetVideoOutputFrameRate(); // AUDIO PARAMETERS _jobLog.WriteEntry(this, ("Setting up audio conversion parameters :") + " " + _audioParams, Log.LogEntryType.Information); AppendParameters(_audioParams); // Audio Parameters // Select the audio language specified by the user if multiple audio languages exist if ((!String.IsNullOrEmpty(_videoFile.RequestedAudioLanguage) || _encoderChooseBestAudioTrack) && (_videoFile.FFMPEGStreamInfo.AudioTracks > 1)) // check if we were requested to isolate a language manually and if there is more than one audio track { _jobLog.WriteEntry(this, ("Selecting Audio Track :") + " " + _videoFile.AudioTrack.ToString(System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Information); SetAudioLanguage(); // Select the right Audio Track if required, do this before we AFTER setting the audio parameters } else _jobLog.WriteEntry(this, ("Skipping over Audio Track selection, no language request or only one Audio Track found"), Log.LogEntryType.Information); // Set the volume if (_volume != 0) // volume is in dB (0dB is no change) { _jobLog.WriteEntry(this, ("Setting up volume adjustment :") + " " + _volume.ToString("#0.0", System.Globalization.CultureInfo.InvariantCulture) + "dB", Log.LogEntryType.Information); if (_audioParams.ToLower().Contains("copy")) _jobLog.WriteEntry(this, ("Copy Audio stream detected, skipping volume settings"), Log.LogEntryType.Warning); else SetAudioVolume(); // do this before we AFTER setting the audio parameters } // Set the DRC with the remaining audio options for most encoders (except ffmpeg) if (_drc) { if ((_videoFile.AudioCodec == "ac-3") || (_videoFile.AudioCodec == "ac3") || (_videoFile.AudioCodec != "e-ac-3") || (_videoFile.AudioCodec != "eac3")) // DRC only applies to AC3 audio { _jobLog.WriteEntry(this, ("Setting up PostDRC"), Log.LogEntryType.Information); if (_audioParams.ToLower().Contains("copy")) _jobLog.WriteEntry(this, ("Copy Audio stream detected, skipping DRC settings"), Log.LogEntryType.Warning); else SetAudioPostDRC(); // do this before we BEFORE setting the input filename } else _jobLog.WriteEntry(this, ("Non AC3 Source Audio, DRC not applicable"), Log.LogEntryType.Information); } //Set audio channels _jobLog.WriteEntry(this, ("Setting up Audio channels"), Log.LogEntryType.Information); SetAudioChannels(); // Multi channel Audio // OUTPUT FILE //Set the output file names _jobLog.WriteEntry(this, ("Setting up Output filename"), Log.LogEntryType.Information); SetOutputFileName(); // Replace user specific parameters in the final command line _jobLog.WriteEntry(this, "Replacing user specified parameters", Log.LogEntryType.Information); ReplaceUserParameters(); // One final santiy check on the parameters before calling the convert function FinalSanityCheck(); //Convert the video - MAIN ONE if (!_jobStatus.Cancelled) { _jobLog.WriteEntry(this, ("Converting the video - Main conversion"), Log.LogEntryType.Information); bool ret = ConvertWithTool(); _jobLog.WriteEntry(this, ("Conversion: Percentage Complete") + " " + _jobStatus.PercentageComplete.ToString(System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, ("Original file size [KB]") + " " + (FileIO.FileSize(SourceVideo) / 1024).ToString("N", System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, ("Finished video conversion, file size [KB]") + " " + (FileIO.FileSize(_convertedFile) / 1024).ToString("N", System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); // TODO: Handbrake sometime fails with a small file conversion and puts out encode done even on a failure, so check filesize. Is there a more reliable way to do this? if (!ret || (FileIO.FileSize(_convertedFile) <= (GlobalDefs.MINIMUM_CONVERTED_FILE_THRESHOLD * (double)FileIO.FileSize(SourceVideo)))) // with unsuccessful or incomplete or if the filesize if less than 1% of the original file { _jobStatus.ErrorMsg = ("Conversion of video failed"); _jobLog.WriteEntry(this, (_jobStatus.ErrorMsg), Log.LogEntryType.Error); return false; } } // EAC3 exception handling - redundant, not required as encoders can handle eac3 audio and function is incorrectly written /* if (!_jobStatus.Cancelled) { _jobLog.WriteEntry(this, ("Checking EAC3 Audio conversion"), Log.LogEntryType.Information); bool ret = ConvertEAC3(); _jobLog.WriteEntry(this, ("EAC3 conversion: Percentage Complete") + " " + _jobStatus.PercentageComplete.ToString(System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, ("Finished EAC3 conversion, file size [KB]") + " " + (FileIO.FileSize(_convertedFile) / 1024).ToString("N", System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); if (!ret || _jobStatus.PercentageComplete == 0 || (FileIO.FileSize(_convertedFile) <= 0)) // Check for total failure as some component like FFMPEG dont' return a correct % { _jobStatus.ErrorMsg = ("Conversion of EAC3 failed"); _jobLog.WriteEntry(this, (_jobStatus.ErrorMsg), Log.LogEntryType.Error); return false; } }*/ // Set the audio delay post conversion if (!_jobStatus.Cancelled) { _jobLog.WriteEntry(this, ("Correcting Audio Delay if required"), Log.LogEntryType.Information); bool ret = FixAudioDelay(); _jobLog.WriteEntry(this, ("Fix Audio Delay: Percentage Complete") + " " + _jobStatus.PercentageComplete.ToString(System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, ("Finished fixing audio delay, file size [KB]") + " " + (FileIO.FileSize(_convertedFile) / 1024).ToString("N", System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); if (!ret || (FileIO.FileSize(_convertedFile) <= 0)) { _jobStatus.ErrorMsg = ("Fix AudioSync failed"); _jobLog.WriteEntry(this, (_jobStatus.ErrorMsg), Log.LogEntryType.Error); return false; } } // Fix the converted filename conflict before remuxing if (!String.IsNullOrEmpty(_renameConvertedFileWithOriginalName)) { try { FileIO.TryFileDelete(_renameConvertedFileWithOriginalName); // Delete if the file with the replacement name exists (sometime with .TS file and TS profiles this happens) File.Move(_convertedFile, _renameConvertedFileWithOriginalName); _convertedFile = _renameConvertedFileWithOriginalName; } catch (Exception e) { _jobStatus.ErrorMsg = ("Unable to rename file after conversion"); _jobLog.WriteEntry(this, ("Unable to rename file after conversion"), Log.LogEntryType.Error); _jobLog.WriteEntry(this, "Error -> " + e.ToString(), Log.LogEntryType.Error); return false; } } // Remux to new Extension if required if (!_jobStatus.Cancelled) { _jobLog.WriteEntry(this, ("Remuxing video if required"), Log.LogEntryType.Information); double fps = 0; double.TryParse(_fps, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out fps); RemuxExt remuxVideo = 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) bool ret = remuxVideo.RemuxFile(); _convertedFile = remuxVideo.RemuxedFile; _jobLog.WriteEntry(this, ("Conversion Remux: Percentage Complete") + " " + _jobStatus.PercentageComplete.ToString(System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); _jobLog.WriteEntry(this, ("Finished conversion remuxing video, file size [KB]") + " " + (FileIO.FileSize(_convertedFile) / 1024).ToString("N", System.Globalization.CultureInfo.InvariantCulture), Log.LogEntryType.Debug); if (!ret || (FileIO.FileSize(_convertedFile) <= 0)) // Check for total failure as some component like FFMPEG dont' return a correct % { _jobStatus.ErrorMsg = ("Remux failed"); _jobLog.WriteEntry(this, (_jobStatus.ErrorMsg), Log.LogEntryType.Error); return false; } } if (!_jobStatus.Cancelled) { if (_removedAds) // We have successfully removed ad's _videoFile.AdsRemoved = true; return true; } else { _jobStatus.ErrorMsg = ("Job cancelled, Aborting conversion"); _jobLog.WriteEntry(this, ("Job cancelled, Aborting conversion"), Log.LogEntryType.Error); return false; } }