Ejemplo n.º 1
0
        internal static void ParseInputLine(IResourceAccessor file, string inputLine, ref MetadataContainer info)
        {
            inputLine = inputLine.Trim();
            int    inputPos     = inputLine.IndexOf("Input #0", StringComparison.InvariantCultureIgnoreCase);
            string ffmContainer = inputLine.Substring(inputPos + 10, inputLine.IndexOf(",", inputPos + 11) - 10).Trim();

            if (info.IsAudio(Editions.DEFAULT_EDITION))
            {
                info.Metadata[Editions.DEFAULT_EDITION].AudioContainerType = FFMpegParseAudioContainer.ParseAudioContainer(ffmContainer, file);
            }
            else if (info.IsVideo(Editions.DEFAULT_EDITION))
            {
                info.Metadata[Editions.DEFAULT_EDITION].VideoContainerType = FFMpegParseVideoContainer.ParseVideoContainer(ffmContainer, file);
            }
            else if (info.IsImage(Editions.DEFAULT_EDITION))
            {
                info.Metadata[Editions.DEFAULT_EDITION].ImageContainerType = FFMpegParseImageContainer.ParseImageContainer(ffmContainer, file);
            }
            else
            {
                info.Metadata[Editions.DEFAULT_EDITION].VideoContainerType = FFMpegParseVideoContainer.ParseVideoContainer(ffmContainer, file);
                info.Metadata[Editions.DEFAULT_EDITION].AudioContainerType = FFMpegParseAudioContainer.ParseAudioContainer(ffmContainer, file);
                info.Metadata[Editions.DEFAULT_EDITION].ImageContainerType = FFMpegParseImageContainer.ParseImageContainer(ffmContainer, file);
            }
        }
Ejemplo n.º 2
0
        public override async Task <MetadataContainer> ParseMediaStreamAsync(IEnumerable <IResourceAccessor> mediaResources)
        {
            bool isImage       = true;
            bool isFileSystem  = false;
            bool isNetwork     = false;
            bool isUnsupported = false;

            //Check all files
            if (!mediaResources.Any())
            {
                throw new ArgumentException($"FFMpegMediaAnalyzer: Resource list is empty", "mediaResources");
            }

            foreach (var res in mediaResources)
            {
                if (res is IFileSystemResourceAccessor fileRes)
                {
                    isFileSystem = true;
                    if (!fileRes.IsFile)
                    {
                        throw new ArgumentException($"FFMpegMediaAnalyzer: Resource '{res.ResourceName}' is not a file", "mediaResources");
                    }
                }
                else if (res is INetworkResourceAccessor urlRes)
                {
                    isNetwork = true;
                }
                else
                {
                    isUnsupported = true;
                }
            }

            if (isFileSystem && isNetwork)
            {
                throw new ArgumentException($"FFMpegMediaAnalyzer: Resources are of mixed media formats", "mediaResources");
            }

            if (isUnsupported)
            {
                throw new ArgumentException($"FFMpegMediaAnalyzer: Resources are of unsupported media formats", "mediaResources");
            }

            ProcessExecutionResult executionResult = null;
            string logFileName = "?";

            if (isFileSystem)
            {
                List <LocalFsResourceAccessorHelper> helpers = new List <LocalFsResourceAccessorHelper>();
                List <IDisposable> accessors = new List <IDisposable>();
                try
                {
                    MetadataContainer info = null;
                    logFileName = mediaResources.First().ResourceName;

                    //Initialize and check file system resources
                    foreach (var res in mediaResources)
                    {
                        string resName = res.ResourceName;
                        if (!(HasImageExtension(resName) || HasVideoExtension(resName) || HasAudioExtension(resName) || HasOpticalDiscFileExtension(resName)))
                        {
                            throw new ArgumentException($"FFMpegMediaAnalyzer: Resource '{res.ResourceName}' has unsupported file extension", "mediaResources");
                        }

                        if (!(HasImageExtension(resName)))
                        {
                            isImage = false;
                        }

                        //Ensure availability
                        var rah = new LocalFsResourceAccessorHelper(res);
                        helpers.Add(rah);
                        var accessor = rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess();
                        if (accessor != null)
                        {
                            accessors.Add(accessor);
                        }
                    }

                    string fileName;
                    if (helpers.Count > 1) //Check if concatenation needed
                    {
                        fileName = $"concat:\"{string.Join("|", helpers.Select(h => h.LocalFsResourceAccessor.LocalFileSystemPath))}\"";
                    }
                    else
                    {
                        fileName = $"\"{helpers.First().LocalFsResourceAccessor.LocalFileSystemPath}\"";
                    }

                    string arguments = "";
                    if (isImage)
                    {
                        //Default image decoder (image2) fails if file name contains å, ø, ö etc., so force format to image2pipe
                        arguments = string.Format("-threads {0} -f image2pipe -i {1}", _analyzerMaximumThreads, fileName);
                    }
                    else
                    {
                        arguments = string.Format("-threads {0} -i {1}", _analyzerMaximumThreads, fileName);
                    }

                    //Use first file for parsing. The other files are expected to be of same encoding and same location
                    var firstFile = helpers.First().LocalFsResourceAccessor;
                    executionResult = await ParseFileAsync(helpers.First().LocalFsResourceAccessor, arguments);

                    if (executionResult != null && executionResult.Success && executionResult.ExitCode == 0 && !string.IsNullOrEmpty(executionResult.StandardError))
                    {
                        //_logger.Debug("MediaAnalyzer: Successfully ran FFProbe:\n {0}", executionResult.StandardError);
                        info = new MetadataContainer();
                        info.AddEdition(Editions.DEFAULT_EDITION);
                        info.Metadata[Editions.DEFAULT_EDITION].Size = helpers.Sum(h => h.LocalFsResourceAccessor.Size);
                        FFMpegParseFFMpegOutput.ParseFFMpegOutput(firstFile, executionResult.StandardError, ref info, _countryCodesMapping);

                        // Special handling for files like OGG which will be falsely identified as videos
                        if (info.Metadata[0].VideoContainerType != VideoContainer.Unknown && info.Video[0].Codec == VideoCodec.Unknown)
                        {
                            info.Metadata[0].VideoContainerType = VideoContainer.Unknown;
                        }

                        if (info.IsImage(Editions.DEFAULT_EDITION) || HasImageExtension(fileName))
                        {
                            info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetFileMime(firstFile, "image/unknown");
                        }
                        else if (info.IsVideo(Editions.DEFAULT_EDITION) || HasVideoExtension(fileName))
                        {
                            info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetFileMime(firstFile, "video/unknown");
                            await _probeLock.WaitAsync();

                            try
                            {
                                FFMpegParseH264Info.ParseH264Info(firstFile, info, _h264MaxDpbMbs, H264_TIMEOUT_MS);
                            }
                            finally
                            {
                                _probeLock.Release();
                            }
                            FFMpegParseMPEG2TSInfo.ParseMPEG2TSInfo(firstFile, info);
                        }
                        else if (info.IsAudio(Editions.DEFAULT_EDITION) || HasAudioExtension(fileName))
                        {
                            info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetFileMime(firstFile, "audio/unknown");
                        }
                        else
                        {
                            return(null);
                        }

                        return(info);
                    }
                }
                finally
                {
                    foreach (var accessor in accessors)
                    {
                        accessor?.Dispose();
                    }
                    foreach (var helper in helpers)
                    {
                        helper?.Dispose();
                    }
                }

                if (executionResult != null)
                {
                    _logger.Error("FFMpegMediaAnalyzer: Failed to extract media type information for resource '{0}', Result: {1}, ExitCode: {2}, Success: {3}", logFileName, executionResult.StandardError, executionResult.ExitCode, executionResult.Success);
                }
                else
                {
                    _logger.Error("FFMpegMediaAnalyzer: Failed to extract media type information for resource '{0}', Execution result empty", logFileName);
                }
            }
            else if (isNetwork)
            {
                //We can only read one network resource so take the first
                var    urlRes = mediaResources.First() as INetworkResourceAccessor;
                string url    = urlRes.URL;

                string arguments = "";
                if (url.StartsWith("rtsp://", StringComparison.InvariantCultureIgnoreCase) == true)
                {
                    arguments += "-rtsp_transport tcp ";
                }
                arguments += "-analyzeduration " + _analyzerStreamTimeout + " ";

                //Resolve host first because ffprobe can hang when resolving host
                var resolvedUrl = UrlHelper.ResolveHostToIPv4Url(url);
                if (string.IsNullOrEmpty(resolvedUrl))
                {
                    throw new InvalidOperationException($"FFMpegMediaAnalyzer: Failed to resolve host for resource '{url}'");
                }
                arguments += string.Format("-i \"{0}\"", resolvedUrl);

                executionResult = await ParseUrlAsync(url, arguments);

                if (executionResult != null && executionResult.Success && executionResult.ExitCode == 0 && !string.IsNullOrEmpty(executionResult.StandardError))
                {
                    //_logger.Debug("MediaAnalyzer: Successfully ran FFProbe:\n {0}", executionResult.StandardError);
                    MetadataContainer info = new MetadataContainer();
                    info.AddEdition(Editions.DEFAULT_EDITION);
                    info.Metadata[Editions.DEFAULT_EDITION].Size = 0;
                    FFMpegParseFFMpegOutput.ParseFFMpegOutput(urlRes, executionResult.StandardError, ref info, _countryCodesMapping);

                    // Special handling for files like OGG which will be falsely identified as videos
                    if (info.Metadata[Editions.DEFAULT_EDITION].VideoContainerType != VideoContainer.Unknown && info.Video[Editions.DEFAULT_EDITION].Codec == VideoCodec.Unknown)
                    {
                        info.Metadata[Editions.DEFAULT_EDITION].VideoContainerType = VideoContainer.Unknown;
                    }

                    if (info.IsImage(Editions.DEFAULT_EDITION))
                    {
                        info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetUrlMime(url, "image/unknown");
                    }
                    else if (info.IsVideo(Editions.DEFAULT_EDITION))
                    {
                        info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetUrlMime(url, "video/unknown");
                        await _probeLock.WaitAsync();

                        try
                        {
                            FFMpegParseH264Info.ParseH264Info(urlRes, info, _h264MaxDpbMbs, H264_TIMEOUT_MS);
                        }
                        finally
                        {
                            _probeLock.Release();
                        }
                        FFMpegParseMPEG2TSInfo.ParseMPEG2TSInfo(urlRes, info);
                    }
                    else if (info.IsAudio(Editions.DEFAULT_EDITION))
                    {
                        info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetUrlMime(url, "audio/unknown");
                    }
                    else
                    {
                        return(null);
                    }
                    return(info);
                }

                if (executionResult != null)
                {
                    _logger.Error("FFMpegMediaAnalyzer: Failed to extract media type information for resource '{0}', Result: {1}, ExitCode: {2}, Success: {3}", url, executionResult.StandardError, executionResult.ExitCode, executionResult.Success);
                }
                else
                {
                    _logger.Error("FFMpegMediaAnalyzer: Failed to extract media type information for resource '{0}', Execution result empty", url);
                }
            }

            return(null);
        }