/// <summary> /// Gets the total number of seconds on the given encode job. /// </summary> /// <param name="job">The encode job to query.</param> /// <param name="title">The title being encoded.</param> /// <returns>The total number of seconds of video to encode.</returns> internal static double GetJobLengthSeconds(EncodeJob job, Title title) { switch (job.RangeType) { case VideoRangeType.All: return title.Duration.TotalSeconds; case VideoRangeType.Chapters: TimeSpan duration = TimeSpan.Zero; for (int i = job.ChapterStart; i <= job.ChapterEnd; i++) { duration += title.Chapters[i - 1].Duration; } return duration.TotalSeconds; case VideoRangeType.Seconds: return job.SecondsEnd - job.SecondsStart; case VideoRangeType.Frames: return (job.FramesEnd - job.FramesStart) / title.Framerate; } return 0; }
public TitleSelectionViewModel(Title title, QueueTitlesDialogViewModel titlesDialogVM) { this.Title = title; this.titlesDialogVM = titlesDialogVM; }
/// <summary> /// Gets the size in bytes for the audio with the given parameters. /// </summary> /// <param name="job">The encode job.</param> /// <param name="lengthSeconds">The length of the encode in seconds.</param> /// <param name="title">The title to encode.</param> /// <param name="outputTrackList">The list of tracks to encode.</param> /// <returns>The size in bytes for the audio with the given parameters.</returns> internal static long GetAudioSize(EncodeJob job, double lengthSeconds, Title title, List<Tuple<AudioEncoding, int>> outputTrackList) { long audioBytes = 0; foreach (Tuple<AudioEncoding, int> outputTrack in outputTrackList) { AudioEncoding encoding = outputTrack.Item1; AudioTrack track = title.AudioTracks[outputTrack.Item2 - 1]; int samplesPerFrame = HandBrakeUtils.GetAudioSamplesPerFrame(encoding.Encoder); int audioBitrate; HBAudioEncoder audioEncoder = Encoders.GetAudioEncoder(encoding.Encoder); if (audioEncoder.IsPassthrough) { // Input bitrate is in bits/second. audioBitrate = track.Bitrate / 8; } else if (encoding.EncodeRateType == AudioEncodeRateType.Quality) { // Can't predict size of quality targeted audio encoding. audioBitrate = 0; } else { int outputBitrate; if (encoding.Bitrate > 0) { outputBitrate = encoding.Bitrate; } else { outputBitrate = Encoders.GetDefaultBitrate( audioEncoder, encoding.SampleRateRaw == 0 ? track.SampleRate : encoding.SampleRateRaw, Encoders.SanitizeMixdown(Encoders.GetMixdown(encoding.Mixdown), audioEncoder, track.ChannelLayout)); } // Output bitrate is in kbps. audioBitrate = outputBitrate * 1000 / 8; } audioBytes += (long)(lengthSeconds * audioBitrate); // Audio overhead audioBytes += encoding.SampleRateRaw * ContainerOverheadPerFrame / samplesPerFrame; } return audioBytes; }
/// <summary> /// Gets a list of encodings and target track indices (1-based). /// </summary> /// <param name="job">The encode job</param> /// <param name="title">The title the job is meant to encode.</param> /// <returns>A list of encodings and target track indices (1-based).</returns> private List<Tuple<AudioEncoding, int>> GetOutputTracks(EncodeJob job, Title title) { var list = new List<Tuple<AudioEncoding, int>>(); foreach (AudioEncoding encoding in job.EncodingProfile.AudioEncodings) { if (encoding.InputNumber == 0) { // Add this encoding for all chosen tracks foreach (int chosenTrack in job.ChosenAudioTracks) { // In normal cases we'll never have a chosen audio track that doesn't exist but when batch encoding // we just choose the first audio track without checking if it exists. if (chosenTrack <= title.AudioTracks.Count) { list.Add(new Tuple<AudioEncoding, int>(encoding, chosenTrack)); } } } else if (encoding.InputNumber <= job.ChosenAudioTracks.Count) { // Add this encoding for the specified track, if it exists int trackNumber = job.ChosenAudioTracks[encoding.InputNumber - 1]; // In normal cases we'll never have a chosen audio track that doesn't exist but when batch encoding // we just choose the first audio track without checking if it exists. if (trackNumber <= title.AudioTracks.Count) { list.Add(new Tuple<AudioEncoding, int>(encoding, trackNumber)); } } } return list; }
/// <summary> /// Calculates the output size for a non-anamorphic job. /// </summary> /// <param name="profile">The encoding profile for the job.</param> /// <param name="title">The title being encoded.</param> /// <returns>The dimensions of the final encode.</returns> private static Size CalculateNonAnamorphicOutput(EncodingProfile profile, Title title) { int sourceWidth = title.Resolution.Width; int sourceHeight = title.Resolution.Height; int width = profile.Width; int height = profile.Height; Cropping crop; if (profile.CustomCropping) { crop = profile.Cropping; } else { crop = title.AutoCropDimensions; } sourceWidth -= crop.Left; sourceWidth -= crop.Right; sourceHeight -= crop.Top; sourceHeight -= crop.Bottom; double croppedAspectRatio = ((double)sourceWidth * title.ParVal.Width) / (sourceHeight * title.ParVal.Height); if (width == 0) { width = sourceWidth; } if (profile.MaxWidth > 0 && width > profile.MaxWidth) { width = profile.MaxWidth; } if (height == 0) { height = sourceHeight; } if (profile.MaxHeight > 0 && height > profile.MaxHeight) { height = profile.MaxHeight; } if (profile.KeepDisplayAspect) { if ((profile.Width == 0 && profile.Height == 0) || profile.Width == 0) { width = (int)((double)height * croppedAspectRatio); if (profile.MaxWidth > 0 && width > profile.MaxWidth) { width = profile.MaxWidth; height = (int)((double)width / croppedAspectRatio); height = GetNearestValue(height, PictureAutoSizeModulus); } width = GetNearestValue(width, PictureAutoSizeModulus); } else if (profile.Height == 0) { height = (int)((double)width / croppedAspectRatio); if (profile.MaxHeight > 0 && height > profile.MaxHeight) { height = profile.MaxHeight; width = (int)((double)height * croppedAspectRatio); width = GetNearestValue(width, PictureAutoSizeModulus); } height = GetNearestValue(height, PictureAutoSizeModulus); } } return new Size(width, height); }
public void SetChosenTracks(List<int> chosenAudioTracks, Title selectedTitle) { DispatchService.Invoke(() => { int previousIndex = this.TargetStreamIndex; this.targetStreams.Clear(); this.targetStreams.Add(new TargetStreamViewModel { Text = CommonRes.All }); int shownStreams = Math.Max(previousIndex, chosenAudioTracks.Count); for (int i = 0; i < shownStreams; i++) { string details = null; if (i < chosenAudioTracks.Count && selectedTitle != null) { details = selectedTitle.AudioTracks[chosenAudioTracks[i] - 1].NoTrackDisplay; } this.targetStreams.Add( new TargetStreamViewModel { Text = string.Format(CommonRes.StreamChoice, (i + 1)), TrackDetails = details }); } // Set to -1, then back to real index in order to force a refresh on the ComboBox this.targetStreamIndex = -1; this.RaisePropertyChanged(() => this.TargetStreamIndex); this.targetStreamIndex = previousIndex; this.RaisePropertyChanged(() => this.TargetStreamIndex); }); }
/// <summary> /// Converts a native title to a Title object. /// </summary> /// <param name="title">The native title structure.</param> /// <returns>The managed Title object.</returns> private Title ConvertTitle(hb_title_s title) { var newTitle = new Title { TitleNumber = title.index, Resolution = new Size(title.width, title.height), ParVal = new Size(title.pixel_aspect_width, title.pixel_aspect_height), Duration = TimeSpan.FromSeconds(title.duration / 90000), AutoCropDimensions = new Cropping { Top = title.crop[0], Bottom = title.crop[1], Left = title.crop[2], Right = title.crop[3] }, AspectRatio = title.aspect, AngleCount = title.angle_count, VideoCodecName = title.video_codec_name, Framerate = ((double)title.rate) / title.rate_base }; switch (title.type) { case hb_title_type_anon.HB_STREAM_TYPE: newTitle.InputType = InputType.Stream; break; case hb_title_type_anon.HB_DVD_TYPE: newTitle.InputType = InputType.Dvd; break; case hb_title_type_anon.HB_BD_TYPE: newTitle.InputType = InputType.Bluray; break; } int currentSubtitleTrack = 1; List<hb_subtitle_s> subtitleList = InteropUtilities.ConvertList<hb_subtitle_s>(title.list_subtitle); foreach (hb_subtitle_s subtitle in subtitleList) { var newSubtitle = new Subtitle { TrackNumber = currentSubtitleTrack, Language = subtitle.lang, LanguageCode = subtitle.iso639_2 }; if (subtitle.format == hb_subtitle_s_subtype.PICTURESUB) { newSubtitle.SubtitleType = SubtitleType.Picture; } else if (subtitle.format == hb_subtitle_s_subtype.TEXTSUB) { newSubtitle.SubtitleType = SubtitleType.Text; } switch (subtitle.source) { case hb_subtitle_s_subsource.CC608SUB: newSubtitle.SubtitleSource = SubtitleSource.CC608; break; case hb_subtitle_s_subsource.CC708SUB: newSubtitle.SubtitleSource = SubtitleSource.CC708; break; case hb_subtitle_s_subsource.SRTSUB: newSubtitle.SubtitleSource = SubtitleSource.SRT; break; case hb_subtitle_s_subsource.SSASUB: newSubtitle.SubtitleSource = SubtitleSource.SSA; break; case hb_subtitle_s_subsource.TX3GSUB: newSubtitle.SubtitleSource = SubtitleSource.TX3G; break; case hb_subtitle_s_subsource.UTF8SUB: newSubtitle.SubtitleSource = SubtitleSource.UTF8; break; case hb_subtitle_s_subsource.VOBSUB: newSubtitle.SubtitleSource = SubtitleSource.VobSub; break; default: break; } newTitle.Subtitles.Add(newSubtitle); currentSubtitleTrack++; } int currentAudioTrack = 1; List<hb_audio_s> audioList = InteropUtilities.ConvertList<hb_audio_s>(title.list_audio); foreach (hb_audio_s audio in audioList) { var newAudio = new AudioTrack { TrackNumber = currentAudioTrack, Codec = Converters.NativeToAudioCodec(audio.config.input.codec), CodecId = audio.config.input.codec, Language = audio.config.lang.simple, LanguageCode = audio.config.lang.iso639_2, Description = audio.config.lang.description, ChannelLayout = audio.config.input.channel_layout, SampleRate = audio.config.input.samplerate, Bitrate = audio.config.input.bitrate }; newTitle.AudioTracks.Add(newAudio); currentAudioTrack++; } List<hb_chapter_s> chapterList = InteropUtilities.ConvertList<hb_chapter_s>(title.list_chapter); foreach (hb_chapter_s chapter in chapterList) { var newChapter = new Chapter { ChapterNumber = chapter.index, Duration = TimeSpan.FromSeconds(((double)chapter.duration) / 90000) }; newTitle.Chapters.Add(newChapter); } return newTitle; }
/// <summary> /// Gets the size in bytes for the audio with the given parameters. /// </summary> /// <param name="job">The encode job.</param> /// <param name="lengthSeconds">The length of the encode in seconds.</param> /// <param name="title">The title to encode.</param> /// <param name="outputTrackList">The list of tracks to encode.</param> /// <returns>The size in bytes for the audio with the given parameters.</returns> internal static long GetAudioSize(EncodeJob job, double lengthSeconds, Title title, List<Tuple<AudioEncoding, int>> outputTrackList) { long audioBytes = 0; foreach (Tuple<AudioEncoding, int> outputTrack in outputTrackList) { AudioEncoding encoding = outputTrack.Item1; AudioTrack track = title.AudioTracks[outputTrack.Item2 - 1]; int samplesPerFrame = HandBrakeUtils.GetAudioSamplesPerFrame(encoding.Encoder); int audioBitrate; if (Utilities.IsPassthrough(encoding.Encoder)) { // Input bitrate is in bits/second. audioBitrate = track.Bitrate / 8; } else { // Output bitrate is in kbps. audioBitrate = encoding.Bitrate * 1000 / 8; } audioBytes += (long)(lengthSeconds * audioBitrate); // Audio overhead audioBytes += encoding.SampleRateRaw * ContainerOverheadPerFrame / samplesPerFrame; } return audioBytes; }
public AudioEncodingViewModel(AudioEncoding audioEncoding, Title selectedTitle, List<int> chosenAudioTracks, string containerName, AudioPanelViewModel audioPanelVM) { this.initializing = true; this.audioPanelVM = audioPanelVM; this.targetStreams = new ObservableCollection<TargetStreamViewModel>(); this.targetStreamIndex = audioEncoding.InputNumber; this.SetChosenTracks(chosenAudioTracks, selectedTitle); this.audioEncoders = new List<AudioEncoderViewModel>(); this.mixdownChoices = new List<MixdownViewModel>(); this.containerName = containerName; this.RefreshEncoderChoices(); HBAudioEncoder hbAudioEncoder = Encoders.GetAudioEncoder(audioEncoding.Encoder); if (hbAudioEncoder.IsPassthrough) { this.selectedAudioEncoder = this.audioEncoders[0]; this.selectedPassthrough = audioEncoding.Encoder; } else { this.selectedAudioEncoder = this.audioEncoders.Skip(1).FirstOrDefault(e => e.Encoder.ShortName == audioEncoding.Encoder); this.selectedPassthrough = "copy"; } if (this.selectedAudioEncoder == null) { this.selectedAudioEncoder = this.audioEncoders[1]; } this.RefreshMixdownChoices(); this.RefreshBitrateChoices(); this.RefreshSampleRateChoices(); this.SelectMixdown(Encoders.GetMixdown(audioEncoding.Mixdown)); this.sampleRate = audioEncoding.SampleRateRaw; if (!this.HBAudioEncoder.SupportsQuality) { this.encodeRateType = AudioEncodeRateType.Bitrate; } else { this.encodeRateType = audioEncoding.EncodeRateType; } this.audioQuality = audioEncoding.Quality; if (audioEncoding.Compression >= 0) { this.audioCompression = audioEncoding.Compression; } else { this.audioCompression = this.HBAudioEncoder.DefaultCompression; } this.selectedBitrate = this.BitrateChoices.SingleOrDefault(b => b.Bitrate == audioEncoding.Bitrate); if (this.selectedBitrate == null) { this.selectedBitrate = this.BitrateChoices.First(); } this.gain = audioEncoding.Gain; this.drc = audioEncoding.Drc; this.passthroughIfPossible = audioEncoding.PassthroughIfPossible; this.name = audioEncoding.Name; Messenger.Default.Register<SelectedTitleChangedMessage>( this, message => { this.RefreshMixdownChoices(); this.RefreshBitrateChoices(); this.RefreshDrc(); }); Messenger.Default.Register<AudioInputChangedMessage>( this, message => { this.RefreshMixdownChoices(); this.RefreshBitrateChoices(); this.RefreshDrc(); }); Messenger.Default.Register<OptionsChangedMessage>( this, message => { this.RaisePropertyChanged(() => this.NameVisible); }); Messenger.Default.Register<ContainerChangedMessage>( this, message => { this.containerName = message.ContainerName; this.RefreshEncoderChoices(); }); this.initializing = false; }
/// <summary> /// Gets the cropping to use for the given encoding profile and title. /// </summary> /// <param name="profile">The encoding profile to use.</param> /// <param name="title">The title being encoded.</param> /// <returns>The cropping to use for the encode.</returns> private static Cropping GetCropping(EncodingProfile profile, Title title) { Cropping crop; switch (profile.CroppingType) { case CroppingType.Automatic: crop = title.AutoCropDimensions; break; case CroppingType.Custom: crop = profile.Cropping; break; default: crop = new Cropping(); break; } return crop; }
/// <summary> /// Gets the 1-based title index of the given title. /// </summary> /// <param name="title">The title to look up</param> /// <returns>The 1-based title index of the given title.</returns> private int GetTitleIndex(Title title) { return this.Titles.IndexOf(title) + 1; }
// Applies the encode job choices to the viewmodel. Part of editing a queued item, // assumes a scan has been done first with the data available. private void ApplyEncodeJobChoices(EncodeJobViewModel jobVM) { if (this.sourceData == null || this.sourceData.Titles.Count == 0) { return; } VCJob job = jobVM.Job; // Title Title newTitle = this.sourceData.Titles.FirstOrDefault(t => t.TitleNumber == job.Title); if (newTitle == null) { newTitle = this.sourceData.Titles[0]; } this.selectedTitle = newTitle; // Angle this.PopulateAnglesList(); if (job.Angle <= this.selectedTitle.AngleCount) { this.angle = job.Angle; } else { this.angle = 0; } // Range this.PopulateChapterSelectLists(); this.rangeType = job.RangeType; if (this.rangeType == VideoRangeType.All) { if (this.selectedTitle.Chapters.Count > 1) { this.rangeType = VideoRangeType.Chapters; } else { this.rangeType = VideoRangeType.Seconds; } } switch (this.rangeType) { case VideoRangeType.Chapters: if (job.ChapterStart > this.selectedTitle.Chapters.Count || job.ChapterEnd > this.selectedTitle.Chapters.Count || job.ChapterStart == 0 || job.ChapterEnd == 0) { this.selectedStartChapter = this.StartChapters.FirstOrDefault(c => c.Chapter == this.selectedTitle.Chapters[0]); this.selectedEndChapter = this.EndChapters.FirstOrDefault(c => c.Chapter == this.selectedTitle.Chapters[this.selectedTitle.Chapters.Count - 1]); } else { this.selectedStartChapter = this.StartChapters.FirstOrDefault(c => c.Chapter == this.selectedTitle.Chapters[job.ChapterStart - 1]); this.selectedEndChapter = this.EndChapters.FirstOrDefault(c => c.Chapter == this.selectedTitle.Chapters[job.ChapterEnd - 1]); } break; case VideoRangeType.Seconds: if (this.selectedTitle.Duration == TimeSpan.Zero) { throw new InvalidOperationException("Title's duration is 0, cannot continue."); } if (job.SecondsStart < this.selectedTitle.Duration.TotalSeconds + 1 && job.SecondsEnd < this.selectedTitle.Duration.TotalSeconds + 1) { TimeSpan startTime = TimeSpan.FromSeconds(job.SecondsStart); TimeSpan endTime = TimeSpan.FromSeconds(job.SecondsEnd); if (endTime > this.selectedTitle.Duration) { endTime = this.selectedTitle.Duration; } if (startTime > endTime - Constants.TimeRangeBuffer) { startTime = endTime - Constants.TimeRangeBuffer; } if (startTime < TimeSpan.Zero) { startTime = TimeSpan.Zero; } this.SetRangeTimeStart(startTime); this.SetRangeTimeEnd(endTime); } else { this.SetRangeTimeStart(TimeSpan.Zero); this.SetRangeTimeEnd(this.selectedTitle.Duration); } // We saw a problem with a job getting seconds 0-0 after a queue edit, add some sanity checking. if (this.TimeRangeEnd == TimeSpan.Zero) { this.SetRangeTimeEnd(this.selectedTitle.Duration); } break; case VideoRangeType.Frames: if (job.FramesStart < this.selectedTitle.Frames + 1 && job.FramesEnd < this.selectedTitle.Frames + 1) { this.framesRangeStart = job.FramesStart; this.framesRangeEnd = job.FramesEnd; } else { this.framesRangeStart = 0; this.framesRangeEnd = this.selectedTitle.Frames; } break; default: throw new ArgumentOutOfRangeException(); } // Audio tracks this.AudioChoices.Clear(); foreach (int chosenTrack in job.ChosenAudioTracks) { if (chosenTrack <= this.selectedTitle.AudioTracks.Count) { this.AudioChoices.Add(new AudioChoiceViewModel { SelectedIndex = chosenTrack - 1 }); } } // Subtitles (standard+SRT) this.CurrentSubtitles.SourceSubtitles = new List<SourceSubtitle>(); this.CurrentSubtitles.SrtSubtitles = new List<SrtSubtitle>(); if (job.Subtitles.SourceSubtitles != null) { foreach (SourceSubtitle sourceSubtitle in job.Subtitles.SourceSubtitles) { if (sourceSubtitle.TrackNumber <= this.selectedTitle.Subtitles.Count) { this.CurrentSubtitles.SourceSubtitles.Add(sourceSubtitle); } } } if (job.Subtitles.SrtSubtitles != null) { foreach (SrtSubtitle srtSubtitle in job.Subtitles.SrtSubtitles) { this.CurrentSubtitles.SrtSubtitles.Add(srtSubtitle); } } // Custom chapter markers this.UseDefaultChapterNames = job.UseDefaultChapterNames; if (job.UseDefaultChapterNames) { this.CustomChapterNames = null; } else { if (this.CustomChapterNames != null && this.selectedTitle.Chapters.Count == this.CustomChapterNames.Count) { this.CustomChapterNames = job.CustomChapterNames; } } // Output path this.OutputPathVM.OutputPath = job.OutputPath; this.OutputPathVM.SourceParentFolder = jobVM.SourceParentFolder; this.OutputPathVM.ManualOutputPath = jobVM.ManualOutputPath; this.OutputPathVM.NameFormatOverride = jobVM.NameFormatOverride; // Encode profile handled above this in EditJob this.RaisePropertyChanged(() => this.SourceIcon); this.RaisePropertyChanged(() => this.SourceText); this.RaisePropertyChanged(() => this.SelectedTitle); this.RaisePropertyChanged(() => this.SelectedStartChapter); this.RaisePropertyChanged(() => this.SelectedEndChapter); this.RaisePropertyChanged(() => this.StartChapters); this.RaisePropertyChanged(() => this.EndChapters); this.RaisePropertyChanged(() => this.TimeRangeStart); this.RaisePropertyChanged(() => this.TimeRangeStartBar); this.RaisePropertyChanged(() => this.TimeRangeEnd); this.RaisePropertyChanged(() => this.TimeRangeEndBar); this.RaisePropertyChanged(() => this.FramesRangeStart); this.RaisePropertyChanged(() => this.FramesRangeEnd); this.RaisePropertyChanged(() => this.RangeType); this.RaisePropertyChanged(() => this.UsingChaptersRange); this.RaisePropertyChanged(() => this.RangeBarVisible); this.RaisePropertyChanged(() => this.SecondsRangeVisible); this.RaisePropertyChanged(() => this.FramesRangeVisible); this.RaisePropertyChanged(() => this.SubtitlesSummary); this.RaisePropertyChanged(() => this.ChapterMarkersSummary); this.RaisePropertyChanged(() => this.ShowChapterMarkerUI); this.RaisePropertyChanged(() => this.Angle); this.RaisePropertyChanged(() => this.Angles); this.RefreshRangePreview(); }
// Automatically pick the correct subtitles on the given job. // Only relies on input from settings and the current title. private void AutoPickSubtitles(VCJob job, Title title, bool useCurrentContext = false) { job.Subtitles = new Subtitles { SourceSubtitles = new List<SourceSubtitle>(), SrtSubtitles = new List<SrtSubtitle>() }; switch (CustomConfig.AutoSubtitle) { case AutoSubtitleType.Disabled: // Only pick subtitles when we have previous context. if (useCurrentContext) { foreach (SourceSubtitle sourceSubtitle in this.main.CurrentSubtitles.SourceSubtitles) { if (sourceSubtitle.TrackNumber == 0) { job.Subtitles.SourceSubtitles.Add(sourceSubtitle.Clone()); } else if ( title.Subtitles.Count > sourceSubtitle.TrackNumber - 1 && this.main.SelectedTitle.Subtitles[sourceSubtitle.TrackNumber - 1].LanguageCode == title.Subtitles[sourceSubtitle.TrackNumber - 1].LanguageCode) { job.Subtitles.SourceSubtitles.Add(sourceSubtitle.Clone()); } } } break; case AutoSubtitleType.ForeignAudioSearch: job.Subtitles.SourceSubtitles.Add( new SourceSubtitle { TrackNumber = 0, BurnedIn = Config.AutoSubtitleBurnIn, Forced = true, Default = true }); break; case AutoSubtitleType.Language: string languageCode = Config.SubtitleLanguageCode; bool audioSame = false; bool burnIn = Config.AutoSubtitleLanguageBurnIn; if (job.ChosenAudioTracks.Count > 0 && title.AudioTracks.Count > 0) { if (title.AudioTracks[job.ChosenAudioTracks[0] - 1].LanguageCode == languageCode) { audioSame = true; } } if (!Config.AutoSubtitleOnlyIfDifferent || !audioSame) { List<Subtitle> nativeSubtitles = title.Subtitles.Where(subtitle => subtitle.LanguageCode == languageCode).ToList(); if (nativeSubtitles.Count > 0) { if (Config.AutoSubtitleAll) { foreach (Subtitle subtitle in nativeSubtitles) { job.Subtitles.SourceSubtitles.Add(new SourceSubtitle { BurnedIn = false, Default = false, Forced = false, TrackNumber = subtitle.TrackNumber }); } } else { job.Subtitles.SourceSubtitles.Add(new SourceSubtitle { BurnedIn = burnIn, Default = false, Forced = false, TrackNumber = nativeSubtitles[0].TrackNumber }); } } } break; case AutoSubtitleType.All: foreach (Subtitle subtitle in title.Subtitles) { job.Subtitles.SourceSubtitles.Add( new SourceSubtitle { TrackNumber = subtitle.TrackNumber, BurnedIn = false, Default = false, Forced = false }); } break; default: throw new ArgumentOutOfRangeException(); } }
// Automatically pick the correct audio on the given job. // Only relies on input from settings and the current title. private void AutoPickAudio(VCJob job, Title title, bool useCurrentContext = false) { job.ChosenAudioTracks = new List<int>(); switch (CustomConfig.AutoAudio) { case AutoAudioType.Disabled: if (title.AudioTracks.Count > 0) { if (useCurrentContext) { // With previous context, pick similarly foreach (AudioChoiceViewModel audioVM in this.main.AudioChoices) { int audioIndex = audioVM.SelectedIndex; if (title.AudioTracks.Count > audioIndex && this.main.SelectedTitle.AudioTracks[audioIndex].LanguageCode == title.AudioTracks[audioIndex].LanguageCode) { job.ChosenAudioTracks.Add(audioIndex + 1); } } // If we didn't manage to match any existing audio tracks, use the first audio track. if (this.main.AudioChoices.Count > 0 && job.ChosenAudioTracks.Count == 0) { job.ChosenAudioTracks.Add(1); } } else { // With no previous context, just pick the first track job.ChosenAudioTracks.Add(1); } } break; case AutoAudioType.Language: List<AudioTrack> nativeTracks = title.AudioTracks.Where(track => track.LanguageCode == Config.AudioLanguageCode).ToList(); if (nativeTracks.Count > 0) { if (Config.AutoAudioAll) { foreach (AudioTrack audioTrack in nativeTracks) { job.ChosenAudioTracks.Add(audioTrack.TrackNumber); } } else { job.ChosenAudioTracks.Add(nativeTracks[0].TrackNumber); } } break; case AutoAudioType.All: foreach (AudioTrack audioTrack in title.AudioTracks) { job.ChosenAudioTracks.Add(audioTrack.TrackNumber); } break; default: throw new ArgumentOutOfRangeException(); } // If none get chosen, pick the first one. if (job.ChosenAudioTracks.Count == 0 && title.AudioTracks.Count > 0) { job.ChosenAudioTracks.Add(1); } }