Exemple #1
0
        private static async Task <FFProbeResult> ProbeVideo(string inputPath)
        {
            var p = await Runner.ExecWithStdoutRedirect("ffprobe", new[]
            {
                "-show_format", "-show_streams", "-print_format", "json", "-loglevel", "quiet", inputPath
            });

            if (p.ExitCode != 0)
            {
                throw new Exception("could not probe video format");
            }

            var probeResult = p.StandardOutput.ReadToEnd();
            var result      = FFProbeResult.FromJson(probeResult);

            return(result);
        }
Exemple #2
0
        /// <summary>
        /// Normalizes the FF probe result.
        /// </summary>
        /// <param name="result">The result.</param>
        private void NormalizeFFProbeResult(FFProbeResult result)
        {
            if (result.format != null && result.format.tags != null)
            {
                result.format.tags = ConvertDictionaryToCaseInSensitive(result.format.tags);
            }

            if (result.streams != null)
            {
                // Convert all dictionaries to case insensitive
                foreach (var stream in result.streams)
                {
                    if (stream.tags != null)
                    {
                        stream.tags = ConvertDictionaryToCaseInSensitive(stream.tags);
                    }

                    if (stream.disposition != null)
                    {
                        stream.disposition = ConvertDictionaryToCaseInSensitive(stream.disposition);
                    }
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// Fetches the specified video.
        /// </summary>
        /// <param name="video">The video.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="data">The data.</param>
        /// <param name="isoMount">The iso mount.</param>
        /// <returns>Task.</returns>
        protected override Task Fetch(Video video, CancellationToken cancellationToken, FFProbeResult data, IIsoMount isoMount)
        {
            return(Task.Run(() =>
            {
                if (data.format != null)
                {
                    // For dvd's this may not always be accurate, so don't set the runtime if the item already has one
                    var needToSetRuntime = video.VideoType != VideoType.Dvd || video.RunTimeTicks == null || video.RunTimeTicks.Value == 0;

                    if (needToSetRuntime && !string.IsNullOrEmpty(data.format.duration))
                    {
                        video.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration)).Ticks;
                    }
                }

                if (data.streams != null)
                {
                    video.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format)).ToList();
                }

                if (data.Chapters != null)
                {
                    video.Chapters = data.Chapters;
                }

                if (video.Chapters == null || video.Chapters.Count == 0)
                {
                    AddDummyChapters(video);
                }

                if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay))
                {
                    var inputPath = isoMount != null ? isoMount.MountedPath : video.Path;
                    FetchBdInfo(video, inputPath, BdInfoCache, cancellationToken);
                }

                AddExternalSubtitles(video);
            }));
        }
        /// <summary>
        /// Fetches the specified audio.
        /// </summary>
        /// <param name="audio">The audio.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="data">The data.</param>
        /// <param name="isoMount">The iso mount.</param>
        /// <returns>Task.</returns>
        protected override Task Fetch(Audio audio, CancellationToken cancellationToken, FFProbeResult data, IIsoMount isoMount)
        {
            return(Task.Run(() =>
            {
                if (data.streams == null)
                {
                    Logger.Error("Audio item has no streams: " + audio.Path);
                    return;
                }

                audio.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format)).ToList();

                // Get the first audio stream
                var stream = data.streams.First(s => s.codec_type.Equals("audio", StringComparison.OrdinalIgnoreCase));

                // Get duration from stream properties
                var duration = stream.duration;

                // If it's not there go into format properties
                if (string.IsNullOrEmpty(duration))
                {
                    duration = data.format.duration;
                }

                // If we got something, parse it
                if (!string.IsNullOrEmpty(duration))
                {
                    audio.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration)).Ticks;
                }

                if (data.format.tags != null)
                {
                    FetchDataFromTags(audio, data.format.tags);
                }
            }));
        }
        public override async Task <ResultType> Run(CancellationToken cancellationToken)
        {
            JobStatus = VideoJobStatus.Running;
            Status    = "Checking files...";

            if (cancellationToken.IsCancellationRequested)
            {
                return(ResultType.Cancelled);
            }

            string file = VideoInfo.VideoId;
            string path = Path.GetDirectoryName(file);
            string name = Path.GetFileNameWithoutExtension(file);

            List <string> ffmpegOptions;
            string        postfixOld;
            string        postfixNew;
            string        outputformat;

            if (VideoInfo is FFMpegReencodeJobVideoInfo)
            {
                FFMpegReencodeJobVideoInfo ffvi = VideoInfo as FFMpegReencodeJobVideoInfo;
                ffmpegOptions = ffvi.FFMpegOptions;
                postfixOld    = ffvi.PostfixOld;
                postfixNew    = ffvi.PostfixNew;
                outputformat  = ffvi.OutputFormat;
            }
            else
            {
                ffmpegOptions = new List <string>()
                {
                    "-c:v", "libx264",
                    "-preset", "slower",
                    "-crf", "23",
                    "-g", "2000",
                    "-c:a", "copy",
                    "-max_muxing_queue_size", "100000",
                };
                postfixOld   = "_chunked";
                postfixNew   = "_x264crf23";
                outputformat = "mp4";
            }
            string ext = "." + outputformat;

            string chunked          = postfixOld;
            string postfix          = postfixNew;
            string newfile          = Path.Combine(path, postfix, name.Substring(0, name.Length - chunked.Length) + postfix + ext);
            string newfileinlocal   = Path.Combine(path, name.Substring(0, name.Length - chunked.Length) + postfix + ext);
            string tempfile         = Path.Combine(path, name.Substring(0, name.Length - chunked.Length) + postfix + "_TEMP" + ext);
            string chunkeddir       = Path.Combine(path, chunked);
            string postfixdir       = Path.Combine(path, postfix);
            string oldfileinchunked = Path.Combine(chunkeddir, Path.GetFileName(file));

            FFProbeResult probe       = null;
            string        encodeinput = null;

            if (await Util.FileExists(file))
            {
                probe = await FFMpegUtil.Probe(file);

                encodeinput = file;
            }
            else if (await Util.FileExists(oldfileinchunked))
            {
                probe = await FFMpegUtil.Probe(oldfileinchunked);

                encodeinput = oldfileinchunked;
            }

            if (probe != null)
            {
                VideoInfo = new FFMpegReencodeJobVideoInfo(file, probe, ffmpegOptions, postfixOld, postfixNew, outputformat);
            }

            // if the input file doesn't exist we might still be in a state where we can set this to finished if the output file already exists, so continue anyway

            bool newfileexists = await Util.FileExists(newfile);

            bool newfilelocalexists = await Util.FileExists(newfileinlocal);

            if (!newfileexists && !newfilelocalexists)
            {
                if (encodeinput == null)
                {
                    // neither input nor output exist, bail
                    Status = "Missing!";
                    return(ResultType.Failure);
                }

                if (await Util.FileExists(tempfile))
                {
                    await Util.DeleteFile(tempfile);
                }

                if (cancellationToken.IsCancellationRequested)
                {
                    return(ResultType.Cancelled);
                }

                Status = "Encoding " + newfile + "...";
                await StallWrite(newfile, new FileInfo( encodeinput ).Length, cancellationToken);

                if (cancellationToken.IsCancellationRequested)
                {
                    return(ResultType.Cancelled);
                }
                Directory.CreateDirectory(postfixdir);
                FFMpegReencodeJobVideoInfo ffmpegVideoInfo = VideoInfo as FFMpegReencodeJobVideoInfo;
                await Reencode(newfile, encodeinput, tempfile, ffmpegVideoInfo.FFMpegOptions);
            }

            if (!newfileexists && newfilelocalexists)
            {
                Directory.CreateDirectory(postfixdir);
                File.Move(newfileinlocal, newfile);
            }

            if (await Util.FileExists(file) && !await Util.FileExists(oldfileinchunked))
            {
                Directory.CreateDirectory(chunkeddir);
                File.Move(file, oldfileinchunked);
            }

            Status    = "Done!";
            JobStatus = VideoJobStatus.Finished;
            return(ResultType.Success);
        }
Exemple #6
0
        private static MediaStream FindVideoStrean(FFProbeResult probeResult)
        {
            var ms = probeResult.Streams.Where(s => s.CodecType == "video").First();

            return(ms);
        }
Exemple #7
0
 /// <summary>
 /// Subclasses must set item values using this
 /// </summary>
 /// <param name="item">The item.</param>
 /// <param name="cancellationToken">The cancellation token.</param>
 /// <param name="result">The result.</param>
 /// <param name="isoMount">The iso mount.</param>
 /// <returns>Task.</returns>
 protected abstract Task Fetch(T item, CancellationToken cancellationToken, FFProbeResult result, IIsoMount isoMount);