示例#1
0
        private static bool HasAcceptableAudio(DConf dc, IMediaInfo mediaInfo)
        {
            if (dc.AcceptedAudioCodecs == null)
            {
                throw new ArgumentNullException(nameof(dc.AcceptedAudioCodecs));
            }
            if (mediaInfo == null)
            {
                throw new ArgumentNullException(nameof(mediaInfo));
            }
            if (mediaInfo.AudioCodec == null)
            {
                throw new ArgumentNullException(nameof(mediaInfo.AudioCodec));
            }

            return(dc.AcceptedAudioCodecs.Contains(mediaInfo.AudioCodec));
        }
示例#2
0
        private static VideoCompatibilityFlags HasAcceptableVideo(DConf dc, SoFakingConfiguration sc, IMediaInfo mediaInfo)
        {
            if (dc.AcceptedVideoCodecs == null)
            {
                throw new ArgumentNullException(nameof(dc.AcceptedVideoCodecs));
            }
            if (mediaInfo == null)
            {
                throw new ArgumentNullException(nameof(mediaInfo));
            }
            if (mediaInfo.VideoCodec == null)
            {
                throw new ArgumentNullException(nameof(mediaInfo.VideoCodec));
            }
            if (mediaInfo.FileInfo == null)
            {
                throw new ArgumentNullException(nameof(mediaInfo.FileInfo));
            }
            if (mediaInfo.HorizontalVideoResolution == -1)
            {
                throw new ArgumentException($"Horizontal resolution invalid: {nameof(mediaInfo.HorizontalVideoResolution)}");
            }

            var acceptableCodec = false;

            foreach (var vc in dc.AcceptedVideoCodecs)
            {
                if (mediaInfo.VideoCodec.IndexOf(vc) >= 0)
                {
                    acceptableCodec = true;
                    break;
                }
            }

            var acceptableResolution = mediaInfo.HorizontalVideoResolution <= sc.MaxHorizontalVideoResolution;
            var acceptableSize       = mediaInfo.FileInfo.Length > (sc.MaxSizeGb * 1024 * 1024);
            // TODO: Fixing getting the video bitrate right would speed up the program significantly.
            // Unfortunately, FFMPEG can't return bitrate of only the video stream. So we will ONLY stream copy if video and all the audio streams combined have a lower bitrate than level 4.2 h264 video bitrate compatible with PS4 (6,25Mbit/s)
            var acceptableBitrate = (mediaInfo.AVBitrateKbs == null || mediaInfo.AVBitrateKbs <= TargetVideoBitrateKbs);

            var flags = VideoCompatibilityFlags.Compatible;

            if (!acceptableCodec)
            {
                flags |= VideoCompatibilityFlags.IncompatibleCodec;
            }
            if (!acceptableResolution)
            {
                flags |= VideoCompatibilityFlags.IncompatibleResolution;
            }
            if (!acceptableSize)
            {
                flags |= VideoCompatibilityFlags.IncompatibleSize;
            }
            if (!acceptableBitrate)
            {
                flags |= VideoCompatibilityFlags.IncompatibleBitrate;
            }

            return(flags);
        }
示例#3
0
        static async Task Main(string[] args)
        {
            if (args.Length == 0)
            {
                throw new Exception("No file to convert provided");
            }

            Console.WriteLine("Encoding: " + args[0]);

            var builder = new ConfigurationBuilder()
                          .SetBasePath(Directory.GetCurrentDirectory())
                          .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                          .AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true) // TODO: Change the Production with Enviroment
                          .AddEnvironmentVariables();

            IConfigurationRoot configuration = builder.Build();
            var encoderConfiguration         = new EncoderConfiguration();

            configuration.GetSection("Encoder").Bind(encoderConfiguration);
            var sofakingConfiguration = new SoFakingConfiguration();

            configuration.GetSection("Sofaking").Bind(sofakingConfiguration);
            var dc = new DConf();

            configuration.GetSection("DownloadFinishedWorker").Bind(dc);

            var builder1 = new HostBuilder()
                           .ConfigureServices((hostContext, services) =>
            {
                services
                .AddSingleton(sofakingConfiguration)
                .AddSingleton(encoderConfiguration)
                .AddSingleton(new SoFakingContextFactory());
            }).UseConsoleLifetime();

            var host = builder1.Build();

            using (var serviceScope = host.Services.CreateScope())
            {
                var        done            = false;
                var        serviceProvider = serviceScope.ServiceProvider;
                var        logger          = new NullLogger <FFMPEGEncoderService>();
                var        flags           = EncodingTargetFlags.None;
                var        videoFile       = args[0];
                IMediaInfo mediaInfo       = null;
                var        useCuda         = true;

                Console.Clear();
                Console.WriteLine($"Is this a film (vs. cartoon)? [y/n]");
                if (Console.ReadKey().KeyChar == 'n')
                {
                    flags |= EncodingTargetFlags.VideoIsAnimation;
                }

                var encoderTranscodingInstance = new FFMPEGEncoderService(logger, encoderConfiguration, sofakingConfiguration);

                try
                {
                    mediaInfo = await encoderTranscodingInstance.GetMediaInfo(videoFile);
                }
                catch (Exception ex)
                {
                    Console.Clear();
                    Console.WriteLine("Can not read media info: " + ex.Message);
                    Console.ReadKey();
                    return;
                }

                // Find subtitles
                var filenameBase = Path.GetFileNameWithoutExtension(videoFile);
                var path         = Path.GetDirectoryName(videoFile);
                var subtitles    = new Dictionary <string, string>();

                foreach (var sl in sofakingConfiguration.SubtitleLanguages)
                {
                    var subPath = Path.Combine(path, filenameBase + $".{sl}.srt");
                    if (File.Exists(subPath))
                    {
                        subtitles.Add(sl, subPath);
                    }
                }

                if (subtitles.Count > 0)
                {
                    Console.Clear();
                    Console.WriteLine($"Found {subtitles.Count} subtitles to embed.");
                    Thread.Sleep(3 * 1000);

                    flags |= EncodingTargetFlags.ExternalSubtitles;
                }


                try
                {
                    var videoAudit = HasAcceptableVideo(dc, sofakingConfiguration, mediaInfo);

                    if (videoAudit != VideoCompatibilityFlags.Compatible)
                    {
                        Console.Clear();
                        Console.WriteLine("Video details:");
                        if (videoAudit.HasFlag(VideoCompatibilityFlags.IncompatibleCodec))
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        Console.WriteLine($"   Codec: {mediaInfo.VideoCodec}, (Accepted: {string.Join(", ", dc.AcceptedVideoCodecs)})");
                        Console.ResetColor();
                        if (videoAudit.HasFlag(VideoCompatibilityFlags.IncompatibleResolution))
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        Console.WriteLine($"   H. Resolution: {mediaInfo.HorizontalVideoResolution}px, (Max: {sofakingConfiguration.MaxHorizontalVideoResolution}px)");
                        Console.ResetColor();
                        if (videoAudit.HasFlag(VideoCompatibilityFlags.IncompatibleBitrate))
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        Console.WriteLine($"   Avg bitrate: {(mediaInfo.AVBitrateKbs.HasValue ? ByteSize.FromKiloBytes(mediaInfo.AVBitrateKbs.Value).ToString() : "?")}/s, (Max: {ByteSize.FromKiloBytes(TargetVideoBitrateKbs)}/s");
                        Console.ResetColor();
                        if (videoAudit.HasFlag(VideoCompatibilityFlags.IncompatibleSize))
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        Console.WriteLine($"   Size: {ByteSize.FromBytes(mediaInfo.FileInfo.Length)} (Max: {ByteSize.FromGigaBytes(sofakingConfiguration.MaxSizeGb)})");
                        Console.ResetColor();
                        Console.WriteLine();

                        Console.WriteLine($"Video needs converting. Continue? [y/n]");
                        if (Console.ReadKey().KeyChar == 'n')
                        {
                            return;
                        }

                        if (encoderConfiguration.CanUseCuda)
                        {
                            Console.Clear();
                            Console.WriteLine($"Use CUDA? [y/n]");
                            if (Console.ReadKey().KeyChar == 'n')
                            {
                                useCuda = false;;
                            }
                        }

                        flags |= EncodingTargetFlags.NeedsNewVideo;
                    }
                }
                catch (ArgumentException ex)
                {
                    Console.Clear();
                    Console.WriteLine("Incompatible video: " + ex.Message);
                    Console.ReadKey();
                    return;
                }

                try
                {
                    if (!HasAcceptableAudio(dc, mediaInfo))
                    {
                        Console.Clear();
                        Console.WriteLine($"Audio ({mediaInfo.AudioCodec}, (Accepted: {string.Join(", ", dc.AcceptedAudioCodecs)})) needs converting. Continue? [y/n]");
                        if (Console.ReadKey().KeyChar == 'n')
                        {
                            return;
                        }

                        flags |= EncodingTargetFlags.NeedsNewAudio;
                    }
                }
                catch (ArgumentException ex)
                {
                    Console.Clear();
                    Console.WriteLine("Incompatible audio: " + ex.Message);
                    Console.ReadKey();
                    return;
                }

                if (flags == EncodingTargetFlags.None)
                {
                    Console.Clear();
                    Console.WriteLine($"Video file {videoFile} doesn't need transcoding, adding to files to move.");
                    Console.ReadKey();
                    return;
                }

                Console.Clear();
                Console.WriteLine("Converting...");

                encoderTranscodingInstance.OnSuccess += (object sender, EncodingSuccessEventArgs e) => {
                    done = true;
                };

                encoderTranscodingInstance.OnProgress += (object sender, EncodingProgressEventArgs e) => {
                    Console.Clear();
                    Console.WriteLine($"Transcoding progress: {e.ProgressPercent:0.##}%");
                };

                // non-blocking, only starts the external engine
                await encoderTranscodingInstance.StartTranscodingAsync(new TranscodingJob
                {
                    SourceFile = videoFile,
                    Action     = flags,
                    Duration   = mediaInfo.Duration,
                    Subtitles  = subtitles,
                    UseCuda    = useCuda
                });

                while (!done)
                {
                    // wait until encoding finished
                }

                Console.Clear();
                Console.WriteLine("Done!");
                Thread.Sleep(3 * 1000);
            }
        }