コード例 #1
0
        public void AnalyzeVideoFile(
            MediaAnalyzeFileRequest request,
            CurveFittingSettings curveFittingSettings,
            MediaAnalyzeActions actions
            )
        {
            // Sanity checks
            if (request.MaxAllowedHeight > request.MaxAllowedWidth)
            {
                throw new ArgumentException(nameof(request), $"{nameof(request.MaxAllowedWidth)} must be always greater than {nameof(request.MaxAllowedHeight)}!");
            }

            // Get the Data for calculating the CurveFittingFunction
            var data = curveFittingSettings.Data.ToDictionary(
                k => (double)k.Width * k.Height,
                v => (double)v.Bitrate / (double)(v.Width * v.Height)
                );

            // Get the CurveFitting Function
            var targetFunction = new CurveFittingFactory()
                                 .GetCurveFittingService(curveFittingSettings.CurveFittingType)
                                 .GetCurveFittingFunction(data);

            // Call the internal recursive method
            AnalyzeVideoFileInternal(request, targetFunction, actions);
        }
コード例 #2
0
        private void AnalyzeVideoFileInternal(
            MediaAnalyzeFileRequest request,
            Func <double, double> targetFunction,
            MediaAnalyzeActions actions
            )
        {
            // Sanity checks
            if (request.MaxAllowedHeight > request.MaxAllowedWidth)
            {
                throw new ArgumentException(nameof(request), $"{nameof(request.MaxAllowedWidth)} must be always greater than {nameof(request.MaxAllowedHeight)}!");
            }

            actions.SetCurrentFileAction(request.MediaFile);

            using (gMediaInfo mi = new gMediaInfo(request.MediaFile))
            {
                if (mi == null)
                {
                    actions.LogErrorAction($"ERROR! {request.MediaFile}");
                    return;
                }

                MediaAnalyzeInfo result = new MediaAnalyzeInfo
                {
                    Filename           = request.MediaFile,
                    Size               = new FileInfo(request.MediaFile).Length,
                    NeedsVideoReencode = false,
                    NeedsAudioReencode = false
                };

                // Get first General track
                var generalTrack = mi?.GeneralTracks?.FirstOrDefault();
                if (generalTrack == null)
                {
                    actions.LogErrorAction($"ERROR! {request.MediaFile}");
                    return;
                }

                // Get more info
                result.FileExtension       = generalTrack.FileExtension;
                result.FileContainerFormat = generalTrack.Format;

                // Get first video track
                var videoTrack = mi?.VideoTracks?.FirstOrDefault();
                if (videoTrack == null)
                {
                    actions.LogErrorAction($"ERROR! {request.MediaFile}");
                    return;
                }

                // Check if we have valid video track info
                if (int.TryParse(videoTrack.Width, out int width) &&
                    int.TryParse(videoTrack.Height, out int height) &&
                    (
                        int.TryParse(videoTrack.BitRate, out int bitrate) ||
                        (videoTrack.BitRate.Contains("/") && int.TryParse(videoTrack.BitRate.Substring(videoTrack.BitRate.IndexOf("/") + 1), out bitrate)) ||
                        int.TryParse(videoTrack.BitRateNominal, out bitrate) ||
                        (videoTrack.BitRateNominal.Contains("/") && int.TryParse(videoTrack.BitRateNominal.Substring(videoTrack.BitRate.IndexOf("/") + 1), out bitrate))
                    )
                    )
                {
                    MediaAnalyzeVideoInfo videoResult = new MediaAnalyzeVideoInfo();
                    // Check for pixel aspect ration
                    if (videoTrack.PixelAspectRatio.TryParseDecimal(out decimal pixelAspectRatio))
                    {
                        // Check if pixel aspect ration is not equal to 1
                        if (pixelAspectRatio > 1.0m)
                        {
                            // Recalculate width based on the pixel aspect ration
                            width = Convert.ToInt32(Math.Ceiling(width * pixelAspectRatio));
                        }
                    }

                    videoResult.Width   = width;
                    videoResult.Height  = height;
                    videoResult.Bitrate = bitrate;
                    videoResult.CodecID = videoTrack.CodecID;
                    videoResult.Size    = long.TryParse(videoTrack.StreamSize, out long streamSize) ? streamSize : default;
                    videoResult.Length  = long.TryParse(videoTrack.Duration, out long videoDuration) ? videoDuration : default;
                    // Get the video FrameRate Mode
                    videoResult.FrameRateMode = videoTrack.FrameRateMode.ToLower().Equals("vfr") ? VideoFrameRateMode.VFR : VideoFrameRateMode.CFR;

                    videoResult.ChromaSubsampling = videoTrack.ChromaSubsampling;
                    videoResult.ColorSpace        = videoTrack.ColorSpace;

                    videoResult.Rotation = videoTrack.Rotation;

                    result.VideoInfo = videoResult;
                }
                else
                {
                    actions.LogErrorAction($"ERROR! {videoTrack.Width}x{videoTrack.Height} : {videoTrack.BitRate} : {videoTrack.CodecID} : {request.MediaFile}");
                    return;
                }

                // Get audio tracks
                var audioTracks = mi?.AudioTracks;

                // Get audio track
                var audioTrack = audioTracks?.FirstOrDefault();

                // Check if we have valid audio track info
                if (audioTrack != null &&
                    int.TryParse(audioTrack.Channels, out int audioChannels) &&
                    (int.TryParse(audioTrack.BitRate, out int audioBitrate) ||
                     int.TryParse(audioTrack.BitRateNominal, out audioBitrate)))
                {
                    MediaAnalyzeAudioInfo audioResult = new MediaAnalyzeAudioInfo();
                    audioResult.Channels = audioChannels;
                    audioResult.Bitrate  = audioBitrate;
                    audioResult.Codec    = audioTrack.FormatString;
                    audioResult.Size     = long.TryParse(audioTrack.StreamSize, out long audioSize) ? audioSize : default;
                    audioResult.Length   = long.TryParse(audioTrack.Duration, out long audioDuration) ? audioDuration : default;

                    result.AudioInfo = audioResult;
                }

                // Check if we need to re encode the video track
                bool isCandidateForVideoReencode = IsCandidateForVideoReencode(width, height, bitrate, request.MaxAllowedWidth, request.MaxAllowedHeight, request.BitratePercentageThreshold, targetFunction, out int targetBitrate, out int targetWidth, out int targetHeight);

                if (isCandidateForVideoReencode)
                {
                    // We only care for lower target bitrate and bitrate greater than the min allowed bitrate!
                    if (targetBitrate < bitrate &&
                        targetBitrate > request.MinAllowedBitrate)
                    {
                        // Check if the gain percentage is worth the reencode
                        double gainPercentage = Math.Abs(((double)(targetBitrate - bitrate) / (double)bitrate) * 100.0);
                        if (gainPercentage >= request.GainPercentageThreshold)
                        {
                            // Set that Video needs reencode
                            result.NeedsVideoReencode = true;
                            result.TargetVideoBitrate = targetBitrate;
                            result.TargetVideoWidth   = targetWidth;
                            result.TargetVideoHeight  = targetHeight;

                            _reEncodeFiles++;

                            actions.UpdateProgressAction(_reEncodeFiles, _totalFiles);
                            actions.HandleMediaForReencodeAction(result);

                            // Check for no audio, or more than one audio
                            if (audioTracks == null || !audioTracks.Any() || audioTracks.Count() > 1)
                            {
                                // No audio tracks, nothing to do here
                                return;
                            }

                            // Sanity check, we should have an AudioInfo
                            if (result?.AudioInfo == null)
                            {
                                // No audio info found, nothing to do here
                                return;
                            }

                            // Check if we need to re encode the audio track
                            bool isWindowsMedia = result.FileContainerFormat.ToLower().Trim().Equals("windows media");
                            bool isCandidateForAudioReencode = IsCandidateForAudioReencode(isWindowsMedia, result.AudioInfo.Channels, result.AudioInfo.Bitrate, out int targetAudioBitrate);

                            if (isCandidateForAudioReencode)
                            {
                                result.NeedsAudioReencode = true;
                                result.TargetAudioBitrate = targetAudioBitrate;
                            }
                        }
                    }
                }
            }
        }