public static string GetSubtitleExtension(SubtitleCodec codec) { switch (codec) { case SubtitleCodec.Srt: return("srt"); case SubtitleCodec.MicroDvd: return("sub"); case SubtitleCodec.SubView: return("sub"); case SubtitleCodec.Ass: return("ass"); case SubtitleCodec.Ssa: return("ssa"); case SubtitleCodec.Smi: return("smi"); case SubtitleCodec.WebVtt: return("vtt"); } return("mpts"); }
public static string GetSubtitleMime(SubtitleCodec codec) { switch (codec) { case SubtitleCodec.Srt: return("text/srt"); case SubtitleCodec.MicroDvd: return("text/microdvd"); case SubtitleCodec.SubView: return("text/plain"); case SubtitleCodec.Ass: return("text/x-ass"); case SubtitleCodec.Ssa: return("text/x-ssa"); case SubtitleCodec.Smi: return("smi/caption"); case SubtitleCodec.WebVtt: return("text/vtt"); } return("text/plain"); }
public async Task AddSubtitleWithLanguageAndCodecTest(SubtitleCodec subtitleCodec) { string output = Path.ChangeExtension(Path.GetTempFileName(), FileExtensions.Mkv); string input = Resources.MkvWithAudio; var language = "pol"; IConversionResult result = await(await FFmpeg.Conversions.FromSnippet.AddSubtitle(input, output, Resources.SubtitleSrt, subtitleCodec, language)) .SetPreset(ConversionPreset.UltraFast) .Start(); IMediaInfo outputInfo = await FFmpeg.GetMediaInfo(output); Assert.Equal(TimeSpan.FromSeconds(3071), outputInfo.Duration); Assert.Single(outputInfo.SubtitleStreams); Assert.Single(outputInfo.VideoStreams); Assert.Single(outputInfo.AudioStreams); Assert.Equal(language, outputInfo.SubtitleStreams.First().Language); if (subtitleCodec.ToString() == "copy") { Assert.Equal("subrip", outputInfo.SubtitleStreams.First().Codec); } else if (subtitleCodec.ToString() == "ssa") { Assert.Equal("ass", outputInfo.SubtitleStreams.First().Codec); } else { Assert.Equal(subtitleCodec.ToString(), outputInfo.SubtitleStreams.First().Codec); } }
public static string GetSubtitleContainer(SubtitleCodec codec) { switch (codec) { case SubtitleCodec.Srt: return("srt"); case SubtitleCodec.MicroDvd: return("microdvd"); case SubtitleCodec.SubView: return("subviewer"); case SubtitleCodec.Ass: return("ass"); case SubtitleCodec.Ssa: return("ssa"); case SubtitleCodec.Smi: return("sami"); case SubtitleCodec.MovTxt: return("mov_text"); case SubtitleCodec.DvbSub: return("dvbsub"); case SubtitleCodec.WebVtt: return("webvtt"); } return("copy"); }
public async Task AddSubtitleWithCodecTest(SubtitleCodec subtitleCodec) { string output = Path.ChangeExtension(Path.GetTempFileName(), FileExtensions.Mkv); string input = Resources.MkvWithAudio; IConversionResult result = await(await FFmpeg.Conversions.FromSnippet.AddSubtitle(input, output, Resources.SubtitleSrt, subtitleCodec)) .Start(); IMediaInfo outputInfo = await FFmpeg.GetMediaInfo(output); Assert.Equal(51, outputInfo.Duration.Minutes); Assert.Single(outputInfo.SubtitleStreams); Assert.Single(outputInfo.VideoStreams); Assert.Single(outputInfo.AudioStreams); if (subtitleCodec.ToString() == "copy") { Assert.Equal("subrip", outputInfo.SubtitleStreams.First().Codec); } else if (subtitleCodec.ToString() == "ssa") { Assert.Equal("ass", outputInfo.SubtitleStreams.First().Codec); } else { Assert.Equal(subtitleCodec.ToString(), outputInfo.SubtitleStreams.First().Codec); } }
public static bool IsImageBasedSubtitle(SubtitleCodec codec) { if (codec == SubtitleCodec.DvbSub || codec == SubtitleCodec.VobSub) { return(true); } return(false); }
public static bool IsSubtitleSupportedByContainer(SubtitleCodec codec, VideoContainer sourceContainer, VideoContainer targetContainer) { if (targetContainer != VideoContainer.Unknown && sourceContainer == targetContainer) { return(true); } if (targetContainer == VideoContainer.Matroska && (codec == SubtitleCodec.VobSub || codec == SubtitleCodec.Ass || codec == SubtitleCodec.MicroDvd || codec == SubtitleCodec.Smi || codec == SubtitleCodec.Srt || codec == SubtitleCodec.Ssa || codec == SubtitleCodec.SubView)) { return(true); } if (targetContainer == VideoContainer.Mpeg2Ps && codec == SubtitleCodec.VobSub) { return(true); } if (targetContainer == VideoContainer.Mpeg2Ts && (codec == SubtitleCodec.DvbSub || codec == SubtitleCodec.DvbTxt)) { return(true); } if (targetContainer == VideoContainer.Avi && codec == SubtitleCodec.Srt) { return(true); } if (targetContainer == VideoContainer.Asf && codec == SubtitleCodec.Srt) { return(true); } if (targetContainer == VideoContainer.Hls && codec == SubtitleCodec.MovTxt) { return(true); } if (targetContainer == VideoContainer.M2Ts && codec == SubtitleCodec.VobSub) { return(true); } if (targetContainer == VideoContainer.Mp4 && codec == SubtitleCodec.MovTxt) { return(true); } if (targetContainer == VideoContainer.Hls && codec == SubtitleCodec.WebVtt) { return(true); } if (targetContainer == VideoContainer.Mpeg1 && codec == SubtitleCodec.VobSub) { return(true); } return(false); }
public static string GetSubtitleBaseURL(Guid mediaItemId, EndPointSettings client, out string subMime, out string subExtension) { SubtitleCodec codec = SubtitleCodec.Unknown; subMime = null; subExtension = null; if (UseSoftCodedSubtitle(client, out codec, out subMime) == true) { subExtension = SubtitleHelper.GetSubtitleExtension(codec); string subType = codec.ToString(); return(string.Format(GetBaseResourceURL() + GetResourceUrl(mediaItemId.ToString(), client.ClientId) + "&aspect=SUBTITLE&type={0}&file=subtitle.{1}", subType, subExtension)); } return(null); }
/// <summary> /// Returns the appropriate extension given an subtitle codec /// </summary> /// <param name="subtitleCodec"></param> /// <returns></returns> public static Extension GetSubtitleExtension(SubtitleCodec subtitleCodec) { if (subtitleCodec.Codec == SubtitleCodec.PGS.Codec) { return(Extension.SUP); } if (subtitleCodec.Codec == SubtitleCodec.KATE.Codec) { return(Extension.OGG); } if (subtitleCodec.Codec == SubtitleCodec.TEXT_SSA.Codec || subtitleCodec.Codec == SubtitleCodec.SSA.Codec) { return(Extension.SSA); } if (subtitleCodec.Codec == SubtitleCodec.TEXT_ASS.Codec || subtitleCodec.Codec == SubtitleCodec.ASS.Codec) { return(Extension.ASS); } if (subtitleCodec.Codec == SubtitleCodec.TEXT_ASCII.Codec || subtitleCodec.Codec == SubtitleCodec.TEXT_UTF.Codec) { return(Extension.SRT); } if (subtitleCodec.Codec == SubtitleCodec.TEXT_USF.Codec) { return(Extension.USF); } if (subtitleCodec.Codec == SubtitleCodec.TEXT_WEB.Codec) { return(Extension.WEBVTT); } if (subtitleCodec.Codec == SubtitleCodec.SUB.Codec) { return(Extension.SUB); } throw new UnkownExtentionException($"Unkown extension for codec: {subtitleCodec.Codec}"); }
public static bool UseSoftCodedSubtitle(EndPointSettings client, out SubtitleCodec targetCodec, out string targetMime) { targetCodec = SubtitleCodec.Unknown; targetMime = "text/plain"; if (client.Profile.MediaTranscoding.SubtitleSettings.SubtitleMode == SubtitleSupport.SoftCoded) { targetCodec = client.Profile.MediaTranscoding.SubtitleSettings.SubtitlesSupported[0].Format; if (string.IsNullOrEmpty(client.Profile.MediaTranscoding.SubtitleSettings.SubtitlesSupported[0].Mime) == false) { targetMime = client.Profile.MediaTranscoding.SubtitleSettings.SubtitlesSupported[0].Mime; } else { targetMime = SubtitleHelper.GetSubtitleMime(targetCodec); } return(true); } return(false); }
public async Task BasicTranscode_InputFileWithSubtitles_SkipSubtitlesWithParameter(VideoCodec videoCodec, AudioCodec audioCodec, SubtitleCodec subtitleCodec) { string output = _storageFixture.GetTempFileName(FileExtensions.Mp4); IConversionResult result = await(await FFmpeg.Conversions.FromSnippet.Transcode(Resources.MkvWithSubtitles, output, videoCodec, audioCodec, subtitleCodec, false)).Start(); IMediaInfo mediaInfo = await FFmpeg.GetMediaInfo(output); Assert.Equal(9, mediaInfo.Duration.Seconds); Assert.Single(mediaInfo.VideoStreams); Assert.Single(mediaInfo.AudioStreams); Assert.Empty(mediaInfo.SubtitleStreams); IAudioStream audioStream = mediaInfo.AudioStreams.First(); IVideoStream videoStream = mediaInfo.VideoStreams.First(); Assert.NotNull(videoStream); Assert.NotNull(audioStream); Assert.Equal(videoCodec.ToString(), videoStream.Codec); Assert.Equal(audioCodec.ToString(), audioStream.Codec); Assert.Equal(25, videoStream.Framerate); }
/// <inheritdoc /> public ISubtitleStream SetCodec(SubtitleCodec codec) { string input = codec.ToString(); return(SetCodec($"{input}")); }
protected override async Task <TranscodeContext> TranscodeVideoAsync(string clientId, VideoTranscoding video, double timeStart, double timeDuration, bool waitForBuffer) { FFMpegTranscodeContext context = new FFMpegTranscodeContext(_cacheEnabled, _cachePath); context.TargetDuration = video.SourceMediaDuration; if (timeStart == 0 && video.TargetIsLive == false && _cacheEnabled) { timeDuration = 0; context.Partial = false; } else if (video.TargetVideoContainer == VideoContainer.Hls) { context.Partial = true; } else { video.TargetIsLive = true; context.Partial = true; } if (video.TargetVideoContainer == VideoContainer.Unknown) { video.TargetVideoContainer = video.SourceVideoContainer; } bool embeddedSupported = false; SubtitleCodec embeddedSubCodec = SubtitleCodec.Unknown; if (video.TargetSubtitleSupport == SubtitleSupport.Embedded) { if (video.TargetVideoContainer == VideoContainer.Matroska) { embeddedSupported = true; embeddedSubCodec = SubtitleCodec.Ass; video.TargetSubtitleCodec = SubtitleCodec.Ass; } else if (video.TargetVideoContainer == VideoContainer.Mp4) { embeddedSupported = true; embeddedSubCodec = SubtitleCodec.MovTxt; video.TargetSubtitleCodec = SubtitleCodec.MovTxt; } else if (video.TargetVideoContainer == VideoContainer.Hls) { embeddedSupported = true; embeddedSubCodec = SubtitleCodec.WebVtt; video.TargetSubtitleCodec = SubtitleCodec.WebVtt; } else if (video.TargetVideoContainer == VideoContainer.Avi) { embeddedSupported = true; embeddedSubCodec = SubtitleCodec.Srt; video.TargetSubtitleCodec = SubtitleCodec.Srt; } //else if (video.TargetVideoContainer == VideoContainer.Mpeg2Ts) //{ // embeddedSupported = true; // embeddedSubCodec = SubtitleCodec.DvbSub; // video.TargetSubtitleCodec = SubtitleCodec.VobSub; //} else { _logger.Debug("FFMpegMediaConverter: Container {0} does not support embedded subtitles", video.TargetVideoContainer); } } video.TargetSubtitleMime = SubtitleHelper.GetSubtitleMime(video.TargetSubtitleCodec); video.PreferredSourceSubtitles = await GetSubtitlesAsync(clientId, video, timeStart).ConfigureAwait(false); string transcodingFile = GetTranscodingVideoFileName(video, timeStart, embeddedSupported); transcodingFile = Path.Combine(_cachePath, transcodingFile); if (File.Exists(transcodingFile)) { //Use non-partial transcode if possible TranscodeContext existingContext = await GetExistingTranscodeContextAsync(clientId, video.TranscodeId).ConfigureAwait(false); if (existingContext != null) { existingContext.TargetFile = transcodingFile; if (existingContext.Stream == null) { existingContext.AssignStream(await GetFileStreamAsync(transcodingFile).ConfigureAwait(false)); } if (existingContext.CurrentDuration.TotalSeconds == 0) { double bitrate = 0; if (video.TargetVideoBitrate.HasValue && video.TargetAudioBitrate.HasValue) { bitrate = video.TargetVideoBitrate.Value + video.TargetAudioBitrate.Value; } else if (video.SourceVideoStream.Bitrate.HasValue && video.SourceAudioStreams.Any(a => a.Bitrate > 0)) { bitrate = video.SourceVideoStream.Bitrate.Value + video.SourceAudioStreams.Max(a => a.Bitrate ?? 0); } bitrate *= 1024; //Bitrate in bits/s if (bitrate > 0) { long startByte = Convert.ToInt64((bitrate * timeStart) / 8.0); if (existingContext.Stream.Length > startByte) { return(existingContext); } } } else { if (existingContext.CurrentDuration.TotalSeconds > timeStart) { return(existingContext); } } } else { //Presume that it is a cached file TouchFile(transcodingFile); context.Partial = false; context.TargetFile = transcodingFile; context.AssignStream(await GetFileStreamAsync(transcodingFile).ConfigureAwait(false)); return(context); } } if (video.TargetVideoContainer == VideoContainer.Hls) { long requestedSegmentSequence = requestedSegmentSequence = Convert.ToInt64(timeStart / HLSSegmentTimeInSeconds); if (requestedSegmentSequence > 0) { requestedSegmentSequence--; //1 segment file margin } string pathName = FFMpegPlaylistManifest.GetPlaylistFolderFromTranscodeFile(_cachePath, transcodingFile); string playlist = Path.Combine(pathName, PlaylistManifest.PLAYLIST_MANIFEST_FILE_NAME); string segmentFile = Path.Combine(pathName, requestedSegmentSequence.ToString("00000") + ".ts"); if (File.Exists(playlist) == true && File.Exists(segmentFile) == true) { //Use exisitng context if possible TranscodeContext existingContext = await GetExistingTranscodeContextAsync(clientId, video.TranscodeId).ConfigureAwait(false); if (existingContext != null) { if (existingContext.LastSegment > requestedSegmentSequence) { existingContext.TargetFile = playlist; existingContext.SegmentDir = pathName; if (existingContext.Stream == null) { existingContext.AssignStream(await GetFileStreamAsync(playlist).ConfigureAwait(false)); } existingContext.HlsBaseUrl = video.HlsBaseUrl; return(existingContext); } } else { //Presume that it is a cached file TouchDirectory(pathName); context.Partial = false; context.TargetFile = playlist; context.SegmentDir = pathName; context.HlsBaseUrl = video.HlsBaseUrl; context.AssignStream(await GetFileStreamAsync(playlist).ConfigureAwait(false)); return(context); } } } FFMpegTranscodeData data = new FFMpegTranscodeData(_cachePath) { TranscodeId = video.TranscodeId, ClientId = clientId }; if (string.IsNullOrEmpty(video.TranscoderBinPath) == false) { data.TranscoderBinPath = video.TranscoderBinPath; } if (string.IsNullOrEmpty(video.TranscoderArguments) == false) { data.ConcatedFileInput = video.ConcatSourceMediaPaths; data.TranscoderArguments = video.TranscoderArguments; data.InputMediaFilePaths = video.SourceMediaPaths; if (video.PreferredSourceSubtitles != null) { foreach (var mediaSourceIndex in video.PreferredSourceSubtitles.Keys) { foreach (var sub in video.PreferredSourceSubtitles[mediaSourceIndex]) { if (string.IsNullOrEmpty(sub.SourcePath) == false) { data.AddSubtitle(mediaSourceIndex, sub.SourcePath); context.TargetSubtitles.Add(sub.SourcePath); } } } } data.OutputFilePath = transcodingFile; context.TargetFile = transcodingFile; } else { data.Encoder = _ffMpegEncoderHandler.StartEncoding(video.TranscodeId, video.TargetVideoCodec); _ffMpegCommandline.InitTranscodingParameters(video.ConcatSourceMediaPaths, video.SourceMediaPaths, ref data); bool useX26XLib = video.TargetVideoCodec == VideoCodec.H264 || video.TargetVideoCodec == VideoCodec.H265; _ffMpegCommandline.AddTranscodingThreadsParameters(!useX26XLib, ref data); int subCopyStream = -1; if (video.PreferredSourceSubtitles.Any()) { if (video.FirstPreferredSourceSubtitle.IsEmbedded) { subCopyStream = video.FirstPreferredSourceSubtitle.StreamIndex; _ffMpegCommandline.AddSubtitleCopyParameters(video.FirstPreferredSourceSubtitle, data); } else if (embeddedSupported) { foreach (int mediaSourceIndex in video.PreferredSourceSubtitles.Keys) { _ffMpegCommandline.AddSubtitleEmbeddingParameters(mediaSourceIndex, video.PreferredSourceSubtitles[mediaSourceIndex], embeddedSubCodec, timeStart, data); } } else if (video.TargetSubtitleSupport != SubtitleSupport.SoftCoded) { video.TargetSubtitleSupport = SubtitleSupport.HardCoded; //Fallback to hardcoded subtitles _logger.Debug("FFMpegMediaConverter: Soft subs not supported. Fallback to hardcoded subtitles"); } } else { embeddedSupported = false; data.OutputArguments.Add("-sn"); } _ffMpegCommandline.AddTimeParameters(video, timeStart, timeDuration, data); _ffMpegCommandline.AddStreamMapParameters(video, data); FFMpegEncoderConfig encoderConfig = _ffMpegEncoderHandler.GetEncoderConfig(data.Encoder); _ffMpegCommandline.AddVideoParameters(video, data.TranscodeId, encoderConfig, data); _ffMpegCommandline.AddVideoAudioParameters(video, data); var result = await _ffMpegCommandline.AddTargetVideoFormatAndOutputFileParametersAsync(video, transcodingFile, timeStart, data).ConfigureAwait(false); context.TargetFile = result.TranscodingFile; context.CurrentSegment = result.StartSegment; if (video.PreferredSourceSubtitles.Any()) { foreach (var sub in video.PreferredSourceSubtitles.SelectMany(s => s.Value)) { if (string.IsNullOrEmpty(sub.SourcePath) == false) { context.TargetSubtitles.Add(sub.SourcePath); } } } } _logger.Info("FFMpegMediaConverter: Invoking transcoder to transcode video file '{0}' for transcode '{1}' with arguments '{2}'", video.SourceMediaPaths.First().Value, video.TranscodeId, String.Join(", ", data.OutputArguments.ToArray())); context.Start(); context.AssignStream(await ExecuteTranscodingProcessAsync(data, context, waitForBuffer).ConfigureAwait(false)); return(context); }
/// <summary> /// Add subtitle to file. It will be added as new stream so if you want to burn subtitles into video you should use /// BurnSubtitle method. /// </summary> /// <param name="inputPath">Input path</param> /// <param name="outputPath">Output path</param> /// <param name="subtitlePath">Path to subtitle file in .srt format</param> /// <param name="subtitleCodec">The Subtitle Codec to Use to Encode the Subtitles</param> /// <param name="language">Language code in ISO 639. Example: "eng", "pol", "pl", "de", "ger"</param> /// <returns>Conversion result</returns> public async Task <IConversion> AddSubtitle(string inputPath, string outputPath, string subtitlePath, SubtitleCodec subtitleCodec, string language = null) { return(await Task.FromResult(Conversion.AddSubtitle(inputPath, outputPath, subtitlePath, subtitleCodec, language))); }
public static IConversion Transcode(string inputFilePath, string outputFilePath, VideoCodec videoCodec, AudioCodec audioCodec, SubtitleCodec subtitleCodec, bool keepSubtitles = false) { IMediaInfo info = FFmpeg.GetMediaInfo(inputFilePath).GetAwaiter().GetResult(); var conversion = New().SetOutput(outputFilePath); foreach (var stream in info.Streams) { if (stream is IVideoStream videoStream) { // PR #268 We have to force the framerate here due to an FFmpeg bug with videos > 100fps from android devices conversion.AddStream(videoStream.SetCodec(videoCodec).SetFramerate(videoStream.Framerate)); } else if (stream is IAudioStream audioStream) { conversion.AddStream(audioStream.SetCodec(audioCodec)); } else if (stream is ISubtitleStream subtitleStream && keepSubtitles) { conversion.AddStream(subtitleStream.SetCodec(subtitleCodec)); } } return(conversion); }
/// <inheritdoc /> public ISubtitleStream SetCodec(SubtitleCodec codec) { return(SetCodec(codec.ToString())); }
/// <summary> /// Add subtitle to file. It will be added as new stream so if you want to burn subtitles into video you should use /// SetSubtitles method. /// </summary> /// <param name="inputPath">Input path</param> /// <param name="outputPath">Output path</param> /// <param name="subtitlePath">Path to subtitle file in .srt format</param> /// <param name="subtitleCodec">The Subtitle Codec to Use to Encode the Subtitles</param> /// <param name="language">Language code in ISO 639. Example: "eng", "pol", "pl", "de", "ger"</param> /// <returns>Conversion result</returns> internal static IConversion AddSubtitle(string inputPath, string outputPath, string subtitlePath, SubtitleCodec subtitleCodec, string language = null) { IMediaInfo mediaInfo = FFmpeg.GetMediaInfo(inputPath).GetAwaiter().GetResult(); IMediaInfo subtitleInfo = FFmpeg.GetMediaInfo(subtitlePath).GetAwaiter().GetResult(); ISubtitleStream subtitleStream = subtitleInfo.SubtitleStreams.First() .SetLanguage(language); return(New() .AddStream(mediaInfo.VideoStreams) .AddStream(mediaInfo.AudioStreams) .AddStream(subtitleStream.SetCodec(subtitleCodec)) .SetOutput(outputPath)); }
private static bool TryGetCodec(string source, out SubtitleCodec result) { return(SubtitleCodecs.TryGetValue(source.ToUpper(), out result)); }
public async Task BasicTranscode_InputFileWithSubtitles_SkipSubtitles(VideoCodec videoCodec, AudioCodec audioCodec, SubtitleCodec subtitleCodec) { string output = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + FileExtensions.Mp4); IConversionResult result = await(await FFmpeg.Conversions.FromSnippet.Transcode(Resources.MkvWithSubtitles, output, videoCodec, audioCodec, subtitleCodec)).Start(); IMediaInfo mediaInfo = await FFmpeg.GetMediaInfo(output); Assert.Equal(TimeSpan.FromSeconds(9), mediaInfo.Duration); Assert.Single(mediaInfo.VideoStreams); Assert.Single(mediaInfo.AudioStreams); Assert.Empty(mediaInfo.SubtitleStreams); IAudioStream audioStream = mediaInfo.AudioStreams.First(); IVideoStream videoStream = mediaInfo.VideoStreams.First(); Assert.NotNull(videoStream); Assert.NotNull(audioStream); Assert.Equal(videoCodec.ToString(), videoStream.Codec); Assert.Equal(audioCodec.ToString(), audioStream.Codec); Assert.Equal(25, videoStream.Framerate); }
/// <summary> /// Transcode one file to another with destination format and codecs. /// </summary> /// <param name="inputFilePath">Path to file</param> /// <param name="outputFilePath">Path to file</param> /// <param name="audioCodec"> The Audio Codec to Transcode the input to</param> /// <param name="videoCodec"> The Video Codec to Transcode the input to</param> /// <param name="videoCodec"> The Subtitle Codec to Transcode the input to</param> /// <param name="keepSubtitles">Whether to Keep Subtitles in the output video</param> /// <returns>IConversion object</returns> public async Task <IConversion> Transcode(string inputFilePath, string outputFilePath, VideoCodec videoCodec, AudioCodec audioCodec, SubtitleCodec subtitleCodec, bool keepSubtitles = false) { return(await Task.FromResult(Conversion.Transcode(inputFilePath, outputFilePath, videoCodec, audioCodec, subtitleCodec, keepSubtitles))); }
protected override async Task <bool> ConvertSubtitleFileAsync(string clientId, VideoTranscoding video, double timeStart, string transcodingFile, SubtitleStream sourceSubtitle, SubtitleStream res) { SubtitleCodec targetCodec = video.TargetSubtitleCodec; if (targetCodec == SubtitleCodec.Unknown) { targetCodec = sourceSubtitle.Codec; } string tempFile = null; FFMpegTranscodeData data = new FFMpegTranscodeData(_cachePath) { TranscodeId = video.TranscodeId + "_sub", ClientId = clientId }; if (string.IsNullOrEmpty(video.TranscoderBinPath) == false) { data.TranscoderBinPath = video.TranscoderBinPath; } if (string.IsNullOrEmpty(video.TranscoderArguments) == false) { // TODO: not sure if this is working data.TranscoderArguments = video.TranscoderArguments; data.InputMediaFilePaths.Add(0, res.SourcePath); data.InputArguments.Add(0, new List <string>()); } else { tempFile = transcodingFile + ".tmp"; res = await ConvertSubtitleEncodingAsync(res, tempFile, video.TargetSubtitleCharacterEncoding).ConfigureAwait(false); // TODO: not sure if this is working _ffMpegCommandline.InitTranscodingParameters(false, new Dictionary <int, string> { { 0, res.SourcePath } }, ref data); data.InputArguments[0].Add(string.Format("-f {0}", FFMpegGetSubtitleContainer.GetSubtitleContainer(sourceSubtitle.Codec))); if (timeStart > 0) { data.OutputArguments.Add(string.Format(CultureInfo.InvariantCulture, "-ss {0:0.0}", timeStart)); } res.Codec = targetCodec; string subtitleEncoder = "copy"; if (res.Codec == SubtitleCodec.Unknown) { res.Codec = SubtitleCodec.Ass; } if (sourceSubtitle.Codec != res.Codec) { subtitleEncoder = FFMpegGetSubtitleContainer.GetSubtitleContainer(res.Codec); } string subtitleFormat = FFMpegGetSubtitleContainer.GetSubtitleContainer(res.Codec); data.OutputArguments.Add("-vn"); data.OutputArguments.Add("-an"); data.OutputArguments.Add(string.Format("-c:s {0}", subtitleEncoder)); data.OutputArguments.Add(string.Format("-f {0}", subtitleFormat)); } data.OutputFilePath = transcodingFile; _logger.Debug("FFMpegMediaConverter: Invoking transcoder to transcode subtitle file '{0}' for transcode '{1}'", res.SourcePath, data.TranscodeId); bool success = false; var path = ResourcePath.Deserialize(res.SourcePath); if (path.TryCreateLocalResourceAccessor(out var subRes)) { using (var rah = new LocalFsResourceAccessorHelper(subRes)) using (var access = rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess()) { var result = await FFMpegBinary.FFMpegExecuteWithResourceAccessAsync(rah.LocalFsResourceAccessor, data.TranscoderArguments, ProcessPriorityClass.Normal, _transcoderTimeout).ConfigureAwait(false); success = result.Success; } } if (success && File.Exists(transcodingFile) == true) { if (tempFile != null && File.Exists(tempFile)) { File.Delete(tempFile); } res.SourcePath = LocalFsResourceProviderBase.ToProviderPath(transcodingFile); return(true); } return(false); }