Exemple #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MediaComponent"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="streamIndex">Index of the stream.</param>
        /// <exception cref="ArgumentNullException">container</exception>
        /// <exception cref="MediaContainerException">The container exception.</exception>
        protected MediaComponent(MediaContainer container, int streamIndex)
        {
            // Parted from: https://github.com/FFmpeg/FFmpeg/blob/master/fftools/ffplay.c#L2559
            // avctx = avcodec_alloc_context3(NULL);
            Container    = container ?? throw new ArgumentNullException(nameof(container));
            CodecContext = ffmpeg.avcodec_alloc_context3(null);
            RC.Current.Add(CodecContext, $"134: {nameof(MediaComponent)}[{MediaType}].ctor()");
            StreamIndex = streamIndex;
            Stream      = container.InputContext->streams[StreamIndex];
            StreamInfo  = container.MediaInfo.Streams[StreamIndex];

            // Set default codec context options from probed stream
            var setCodecParamsResult = ffmpeg.avcodec_parameters_to_context(CodecContext, Stream->codecpar);

            if (setCodecParamsResult < 0)
            {
                Container.Parent?.Log(MediaLogMessageType.Warning, $"Could not set codec parameters. Error code: {setCodecParamsResult}");
            }

            // We set the packet timebase in the same timebase as the stream as opposed to the tpyical AV_TIME_BASE
            if (this is VideoComponent && Container.MediaOptions.VideoForcedFps > 0)
            {
                var fpsRational = ffmpeg.av_d2q(Container.MediaOptions.VideoForcedFps, 1000000);
                Stream->r_frame_rate       = fpsRational;
                CodecContext->pkt_timebase = new AVRational {
                    num = fpsRational.den, den = fpsRational.num
                };
            }
            else
            {
                CodecContext->pkt_timebase = Stream->time_base;
            }

            // Find the default decoder codec from the stream and set it.
            var      defaultCodec = ffmpeg.avcodec_find_decoder(Stream->codec->codec_id);
            AVCodec *forcedCodec  = null;

            // If set, change the codec to the forced codec.
            if (Container.MediaOptions.DecoderCodec.ContainsKey(StreamIndex) &&
                string.IsNullOrWhiteSpace(Container.MediaOptions.DecoderCodec[StreamIndex]) == false)
            {
                var forcedCodecName = Container.MediaOptions.DecoderCodec[StreamIndex];
                forcedCodec = ffmpeg.avcodec_find_decoder_by_name(forcedCodecName);
                if (forcedCodec == null)
                {
                    Container.Parent?.Log(MediaLogMessageType.Warning,
                                          $"COMP {MediaType.ToString().ToUpperInvariant()}: Unable to set decoder codec to '{forcedCodecName}' on stream index {StreamIndex}");
                }
            }

            // Check we have a valid codec to open and process the stream.
            if (defaultCodec == null && forcedCodec == null)
            {
                var errorMessage = $"Fatal error. Unable to find suitable decoder for {Stream->codec->codec_id.ToString()}";
                CloseComponent();
                throw new MediaContainerException(errorMessage);
            }

            var      codecCandidates = new AVCodec *[] { forcedCodec, defaultCodec };
            AVCodec *selectedCodec   = null;
            var      codecOpenResult = 0;

            foreach (var codec in codecCandidates)
            {
                if (codec == null)
                {
                    continue;
                }

                // Pass default codec stuff to the codec contect
                CodecContext->codec_id = codec->id;
                if ((codec->capabilities & ffmpeg.AV_CODEC_CAP_TRUNCATED) != 0)
                {
                    CodecContext->flags |= ffmpeg.AV_CODEC_FLAG_TRUNCATED;
                }
                if ((codec->capabilities & ffmpeg.AV_CODEC_FLAG2_CHUNKS) != 0)
                {
                    CodecContext->flags |= ffmpeg.AV_CODEC_FLAG2_CHUNKS;
                }

                // Process the decoder options
                {
                    var decoderOptions = Container.MediaOptions.DecoderParams;

                    // Configure the codec context flags
                    if (decoderOptions.EnableFastDecoding)
                    {
                        CodecContext->flags2 |= ffmpeg.AV_CODEC_FLAG2_FAST;
                    }
                    if (decoderOptions.EnableLowDelay)
                    {
                        CodecContext->flags |= ffmpeg.AV_CODEC_FLAG_LOW_DELAY;
                    }

                    // process the low res option
                    if (decoderOptions.EnableLowRes && codec->max_lowres > 0)
                    {
                        decoderOptions.LowResIndex = codec->max_lowres.ToString(CultureInfo.InvariantCulture);
                    }

                    // Ensure ref counted frames for audio and video decoding
                    if (CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO || CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_AUDIO)
                    {
                        decoderOptions.RefCountedFrames = "1";
                    }
                }

                // Setup additional settings. The most important one is Threads -- Setting it to 1 decoding is very slow. Setting it to auto
                // decoding is very fast in most scenarios.
                var codecOptions = Container.MediaOptions.DecoderParams.GetStreamCodecOptions(Stream->index);

                // Enable Hardware acceleration if requested
                if (this is VideoComponent && container.MediaOptions.VideoHardwareDevice != null)
                {
                    HardwareAccelerator.Attach(this as VideoComponent, container.MediaOptions.VideoHardwareDevice);
                }

                // Open the CodecContext. This requires exclusive FFmpeg access
                lock (CodecOpenLock)
                {
                    fixed(AVDictionary **codecOptionsRef = &codecOptions.Pointer)
                    codecOpenResult = ffmpeg.avcodec_open2(CodecContext, codec, codecOptionsRef);
                }

                // Check if the codec opened successfully
                if (codecOpenResult < 0)
                {
                    Container.Parent?.Log(MediaLogMessageType.Warning,
                                          $"Unable to open codec '{FFInterop.PtrToStringUTF8(codec->name)}' on stream {streamIndex}");

                    continue;
                }

                // If there are any codec options left over from passing them, it means they were not consumed
                var currentEntry = codecOptions.First();
                while (currentEntry != null && currentEntry?.Key != null)
                {
                    Container.Parent?.Log(MediaLogMessageType.Warning,
                                          $"Invalid codec option: '{currentEntry.Key}' for codec '{FFInterop.PtrToStringUTF8(codec->name)}', stream {streamIndex}");
                    currentEntry = codecOptions.Next(currentEntry);
                }

                selectedCodec = codec;
                break;
            }

            if (selectedCodec == null)
            {
                CloseComponent();
                throw new MediaContainerException($"Unable to find suitable decoder codec for stream {streamIndex}. Error code {codecOpenResult}");
            }

            // Startup done. Set some options.
            Stream->discard = AVDiscard.AVDISCARD_DEFAULT;
            MediaType       = (MediaType)CodecContext->codec_type;

            // Compute the start time
            if (Stream->start_time == ffmpeg.AV_NOPTS_VALUE)
            {
                StartTimeOffset = Container.MediaStartTimeOffset;
            }
            else
            {
                StartTimeOffset = Stream->start_time.ToTimeSpan(Stream->time_base);
            }

            // compute the duration
            if (Stream->duration == ffmpeg.AV_NOPTS_VALUE || Stream->duration == 0)
            {
                Duration = Container.InputContext->duration.ToTimeSpan();
            }
            else
            {
                Duration = Stream->duration.ToTimeSpan(Stream->time_base);
            }

            CodecId   = Stream->codec->codec_id;
            CodecName = FFInterop.PtrToStringUTF8(selectedCodec->name);
            Bitrate   = Stream->codec->bit_rate < 0 ? 0 : Convert.ToUInt64(Stream->codec->bit_rate);
            Container.Parent?.Log(MediaLogMessageType.Debug,
                                  $"COMP {MediaType.ToString().ToUpperInvariant()}: Start Offset: {StartTimeOffset.Format()}; Duration: {Duration.Format()}");
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="SubtitleComponent"/> class.
 /// </summary>
 /// <param name="container">The container.</param>
 /// <param name="streamIndex">Index of the stream.</param>
 internal SubtitleComponent(MediaContainer container, int streamIndex)
     : base(container, streamIndex)
 {
     // placeholder. Nothing else to change here.
 }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            CpContentDirectory CDS = this.GetCDS(arg._Device);

            _Details        = new CdsResult_BrowseFilterRangeSort();
            this._TestState = UPnPTestStates.Running;
            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" started.");


            // get the results from the prerequisite tests
            CdsResult_BrowseFilter       FILTER_RESULTS = null;
            CdsResult_BrowseRange        RANGE_RESULTS  = null;
            CdsResult_BrowseSortCriteria SORT_RESULTS   = null;

            try
            {
                foreach (ISubTest preTest in otherSubTests)
                {
                    if (preTest.Name == this.PRE_FILTER.Name)
                    {
                        FILTER_RESULTS = preTest.Details as CdsResult_BrowseFilter;
                    }
                    else if (preTest.Name == this.PRE_RANGE.Name)
                    {
                        RANGE_RESULTS = preTest.Details as CdsResult_BrowseRange;
                    }
                    else if (preTest.Name == this.PRE_SORT.Name)
                    {
                        SORT_RESULTS = preTest.Details as CdsResult_BrowseSortCriteria;
                    }
                }

                if (FILTER_RESULTS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_FILTER.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }

                if (RANGE_RESULTS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_RANGE.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }

                if (SORT_RESULTS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_SORT.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }
            }
            catch (Exception e)
            {
                throw new TestException(this._Name + " requires that the \"" + this.PRE_FILTER.Name + "\" and \"" + this.PRE_RANGE + "\" and \"" + this.PRE_SORT + "\" tests be run before. An error occurred when attempting to obtain the results of those prerequisites.", otherSubTests, e);
            }

            UPnPTestStates      state      = this._TestState;
            CdsResult_BrowseAll BROWSE_ALL = FILTER_RESULTS.BrowseAllResults;

            if (BROWSE_ALL.LargestContainer == null)
            {
                throw new TestException(new Cds_BrowseAll().Name + " failed to find the container with the most child objects. " + this._Name + " requires this value.", BROWSE_ALL);
            }
            if (BROWSE_ALL.MostMetadata == null)
            {
                throw new TestException(new Cds_BrowseAll().Name + " failed to find the media object with the most metadata. " + this._Name + " requires this value.", BROWSE_ALL);
            }
            if (SORT_RESULTS.SortFields == null)
            {
                throw new TestException(new Cds_BrowseAll().Name + " failed to find the sortable fields. " + this._Name + " requires this value.", SORT_RESULTS);
            }

            int max = Math.Max(FILTER_RESULTS.Filters.Count, BROWSE_ALL.LargestContainer.ChildCount);

            max = Math.Max(max, SORT_RESULTS.SortFields.Count);

            this._Details.ExpectedTotalBrowseRequests = max + 1;
            this._Details.TotalBrowseRequests         = 0;
            this._ExpectedTestingTime = this._Details.ExpectedTotalBrowseRequests * 900;
            arg.ActiveTests.UpdateTimeAndProgress(this._Details.TotalBrowseRequests * 900);

            state = UPnPTestStates.Pass;
            for (int i = 0; i <= max; i++)
            {
                ArrayList filterList = new ArrayList();
                for (int j = 0; j < i; j++)
                {
                    if (j < FILTER_RESULTS.Filters.Count)
                    {
                        filterList.Add(FILTER_RESULTS.Filters[j]);
                    }
                    else
                    {
                        break;
                    }
                }
                string filterSettings = Cds_BrowseTest.GetCSVString(filterList);


                uint range = (uint)i;
                if (range > BROWSE_ALL.LargestContainer.ChildCount)
                {
                    range = (uint)BROWSE_ALL.LargestContainer.ChildCount;
                }


                ArrayList sortList = new ArrayList();
                for (int j = 0; j < i; j++)
                {
                    if (j < SORT_RESULTS.SortFields.Count)
                    {
                        sortList.Add(SORT_RESULTS.SortFields[j]);
                    }
                    else
                    {
                        break;
                    }
                }

                BrowseInput input = new BrowseInput();
                input.ObjectID       = BROWSE_ALL.LargestContainer.ID;
                input.BrowseFlag     = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN;
                input.Filter         = filterSettings;
                input.RequestedCount = range;
                input.SortCriteria   = Cds_BrowseSortCriteria.GetSortCriteriaString(sortList, i);
                input.StartingIndex  = 0;

                this._ExpectedTestingTime = (max) * 900;
                arg.ActiveTests.UpdateTimeAndProgress(this._Details.TotalBrowseRequests * 900);
                CdsBrowseSearchResults br = Cds_BrowseTest.Browse(input, this, arg, CDS, _Details);

                MediaContainer original = (MediaContainer)BROWSE_ALL.LargestContainer;
                uint           ignored;
                IList          expectedResults;

                expectedResults = original.BrowseSorted(0, input.RequestedCount, new MediaSorter(true, input.SortCriteria), out ignored);

                try
                {
                    if (br.WorstError <= UPnPTestStates.Warn)
                    {
                        if (br.MediaObjects.Count != expectedResults.Count)
                        {
                            throw new TerminateEarly(input.PrintBrowseParams() + " returned DIDL-Lite that declared " + br.MediaObjects.Count + " media objects but test expected " + expectedResults.Count.ToString() + " media objects as found in a prerequisite test.");
                        }

                        bool warnOrder = false;
                        for (int ri = 0; ri < br.MediaObjects.Count; ri++)
                        {
                            IUPnPMedia resultObj   = (IUPnPMedia)br.MediaObjects[ri];
                            IUPnPMedia originalObj = (IUPnPMedia)expectedResults[ri];

                            if (resultObj.ID != originalObj.ID)
                            {
                                warnOrder = true;
                            }

                            foreach (string propName in resultObj.Properties.PropertyNames)
                            {
                                if (filterList.Contains(propName) == false)
                                {
                                    if (
                                        (propName != T[_DC.title]) &&
                                        (propName != T[_UPNP.Class])
                                        )
                                    {
                                        StringBuilder msg = new StringBuilder();
                                        msg.AppendFormat("\"" + this.Name + "\" is terminating early because {0} returned DIDL-Lite with \"{1}\" metadata when it should not have done so.", input.PrintBrowseParams(), propName);
                                        throw new TerminateEarly(msg.ToString());
                                    }
                                }
                            }
                        }

                        int expectedCount = i;
                        if ((i == 0) || (i > BROWSE_ALL.LargestContainer.ChildCount))
                        {
                            expectedCount = BROWSE_ALL.LargestContainer.ChildCount;
                        }

                        if (br.MediaObjects.Count != expectedCount)
                        {
                            StringBuilder msg = new StringBuilder();
                            msg.AppendFormat("\"{0}\" did a {1} and the DIDL-Lite result only has {2} media objects when {3} media objects were expected.", this.Name, input.PrintBrowseParams(), br.MediaObjects.Count, expectedCount);
                            msg.AppendFormat(".\r\nDIDL-Lite ==> {0}", br.Result);
                            throw new TerminateEarly(msg.ToString());
                        }

                        if (warnOrder)
                        {
                            /*
                             * ArrayList missingResults = new ArrayList();
                             *
                             * foreach (IUPnPMedia em in expectedResults)
                             * {
                             *      bool found = false;
                             *      foreach (IUPnPMedia fm in br.MediaObjects)
                             *      {
                             *              if (em.ID == fm.ID)
                             *              {
                             *                      found = true;
                             *                      break;
                             *              }
                             *      }
                             *
                             *      if (found == false)
                             *      {
                             *              missingResults.Add(em);
                             *      }
                             * }
                             *
                             * if (missingResults.Count > 0)
                             * {
                             *      state = UPnPTestStates.Failed;
                             *      StringBuilder msg = new StringBuilder();
                             *      msg.AppendFormat("\"{0}\" did a {1} and the result is missing media objects.", this.Name, input.PrintBrowseParams());
                             *      msg.Append("\r\nExpected order of IDs: ");
                             *      int z = 0;
                             *      foreach (IUPnPMedia em in expectedResults)
                             *      {
                             *              if (z > 0)
                             *              {
                             *                      msg.Append(",");
                             *              }
                             *              msg.AppendFormat("\"{0}\"", em.ID);
                             *              z++;
                             *      }
                             *      msg.Append("\r\nDIDL-Lite result's order of IDs: ");
                             *      z = 0;
                             *      foreach (IUPnPMedia em in br.MediaObjects)
                             *      {
                             *              if (z > 0)
                             *              {
                             *                      msg.Append(",");
                             *              }
                             *              msg.AppendFormat("\"{0}\"", em.ID);
                             *              z++;
                             *      }
                             *      msg.AppendFormat(".\r\nDIDL-Lite ==> {0}", br.Result);
                             *      throw new TerminateEarly(msg.ToString());
                             * }
                             * else
                             */
                            {
                                StringBuilder msg = new StringBuilder();
                                msg.AppendFormat("WARNING: \"{0}\" did a {1} and got items in a different order. Target CDS either has an error in its sorting logic, or sorting logic intentionally deviates from test.", this.Name, input.PrintBrowseParams());
                                msg.Append("\r\nExpected order of IDs: ");
                                int z = 0;
                                foreach (IUPnPMedia em in expectedResults)
                                {
                                    if (z > 0)
                                    {
                                        msg.Append(",");
                                    }
                                    msg.AppendFormat("\"{0}\"", em.ID);
                                    z++;
                                }
                                msg.Append("\r\nDIDL-Lite result's order of IDs: ");
                                z = 0;
                                foreach (IUPnPMedia em in br.MediaObjects)
                                {
                                    if (z > 0)
                                    {
                                        msg.Append(",");
                                    }
                                    msg.AppendFormat("\"{0}\"", em.ID);
                                    z++;
                                }
                                msg.AppendFormat(".\r\nDIDL-Lite ==> {0}", br.Result);
                                arg._TestGroup.AddEvent(LogImportance.Medium, this.Name, msg.ToString());
                                state = UPnPTestStates.Warn;
                            }
                        }
                    }
                    else
                    {
                        throw new TerminateEarly("\"" + this.Name + "\" is terminating early because " + input.PrintBrowseParams() + " returned with an error or had problems with the DIDL-Lite.");
                    }
                }
                catch (TerminateEarly te)
                {
                    arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, "\"" + this.Name + "\" terminating early. Reason ==> " + te.Message);
                    state = UPnPTestStates.Failed;
                    break;
                }
            }


            // finish up logging
            this._TestState = state;

            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("\"{0}\" completed", this.Name);

            if (this._TestState <= UPnPTestStates.Running)
            {
                throw new TestException("\"" + this.Name + "\" must have a pass/warn/fail result.", this._TestState);
            }

            switch (this._TestState)
            {
            case UPnPTestStates.Pass:
                sb.Append(" successfully.");
                break;

            case UPnPTestStates.Warn:
                sb.Append(" with warnings.");
                break;

            case UPnPTestStates.Failed:
                sb.Append(" with a failed result.");
                break;
            }

            arg._TestGroup.AddResult(sb.ToString());

            if (this._TestState <= UPnPTestStates.Warn)
            {
                if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests)
                {
                    throw new TestException("TotalBrowseRequests=" + _Details.TotalBrowseRequests.ToString() + " ExpectedTotal=" + _Details.ExpectedTotalBrowseRequests.ToString(), _Details);
                }
            }

            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, this.Name + " finished.");

            return(this._TestState);
        }
Exemple #4
0
        private int server_BrowseMetadata(Action action, String object_id, String filter, Int32 starting_index, Int32 requested_count, String sort_criteria, HttpRequestContext context)
        {
            Console.WriteLine("BrowseMetadata: " + object_id);
            if (object_id == "0") 
            {
                var root = new MediaContainer();
                root.Title = "Root";
                root.ObjectID = "0";
                root.ParentID = "-1";
                root.Class = new ObjectClass("object.container.storageFolder", "");

                var didl = Didl.header + root.ToDidl(filter) + Didl.footer;
                action.SetArgumentValue("Result", didl);
                action.SetArgumentValue("NumberReturned", "1");
                action.SetArgumentValue("TotalMatches", "1");

                // update ID may be wrong here, it should be the one of the container?
                // TODO: We need to keep track of the overall updateID of the CDS
                action.SetArgumentValue("UpdateId", "1");

                return 0;
            }
            else if (object_id == "1")
            {
                var item = new MediaItem();
                item.Title = "Item";
                item.ObjectID = "1";
                item.ParentID = "0";
                item.Class = new ObjectClass("object.item.audioItem.musicTrack", "");

                var resource = new MediaResource();
                resource.ProtoInfo = ProtocolInfo.GetProtocolInfoFromMimeType("audio/mp3", true, context);

                // get list of ips and make sure the ip the request came from is used for the first resource returned
                // this ensures that clients which look only at the first resource will be able to reach the item
                List<String> ips = UPnP.GetIpAddresses(true);
                String localIP = context.LocalAddress.ip;
                if (localIP != "0.0.0.0")
                {
                    ips.Remove(localIP);
                    ips.Insert(0, localIP);
                }

                // iterate through all ips and create a resource for each
                foreach (String ip in ips)
                {
                    resource.URI = new Uri("http://" + ip + ":" + context.LocalAddress.port + "/test/test.mp3").ToString();
                    item.AddResource(resource);
                }
                                
                var didl = Didl.header + item.ToDidl(filter) + Didl.footer;
                action.SetArgumentValue("Result", didl);
                action.SetArgumentValue("NumberReturned", "1");
                action.SetArgumentValue("TotalMatches", "1");

                // update ID may be wrong here, it should be the one of the container?
                // TODO: We need to keep track of the overall updateID of the CDS
                action.SetArgumentValue("UpdateId", "1");

                return 0;
            }

            return -1;
        }
Exemple #5
0
        /// <summary>
        /// Adds a block to the playback blocks by converting the given frame.
        /// If there are no more blocks in the pool, the oldest block is returned to the pool
        /// and reused for the new block. The source frame is automatically disposed.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="container">The container.</param>
        /// <returns>The filled block.</returns>
        internal MediaBlock Add(MediaFrame source, MediaContainer container)
        {
            if (source == null)
            {
                return(null);
            }

            lock (SyncLock)
            {
                try
                {
                    // Check if we already have a block at the given time
                    if (IsInRange(source.StartTime) && source.HasValidStartTime)
                    {
                        var reapeatedBlock = PlaybackBlocks.FirstOrDefault(f => f.StartTime.Ticks == source.StartTime.Ticks);
                        if (reapeatedBlock != null)
                        {
                            PlaybackBlocks.Remove(reapeatedBlock);
                            PoolBlocks.Enqueue(reapeatedBlock);
                        }
                    }

                    // if there are no available blocks, make room!
                    if (PoolBlocks.Count <= 0)
                    {
                        var firstBlock = PlaybackBlocks[0];
                        PlaybackBlocks.RemoveAt(0);
                        PoolBlocks.Enqueue(firstBlock);
                    }

                    // Get a block reference from the pool and convert it!
                    var targetBlock = PoolBlocks.Dequeue();
                    if (container.Convert(source, ref targetBlock, PlaybackBlocks, true) == false)
                    {
                        // return the converted block to the pool
                        PoolBlocks.Enqueue(targetBlock);
                        return(null);
                    }

                    // Add the converted block to the playback list and sort it if we have to.
                    var lastBlock       = PlaybackBlocks.Count > 0 ? PlaybackBlocks[PlaybackBlocks.Count - 1] : null;
                    var requiresSorting = lastBlock != null && targetBlock.StartTime < lastBlock.StartTime;

                    PlaybackBlocks.Add(targetBlock);
                    var maxBlockIndex = PlaybackBlocks.Count - 1;

                    // Perform the sorting and assignment of Previous and Next blocks
                    if (requiresSorting)
                    {
                        PlaybackBlocks.Sort();
                        PlaybackBlocks[0].Index    = 0;
                        PlaybackBlocks[0].Previous = null;
                        PlaybackBlocks[0].Next     = maxBlockIndex > 0 ? PlaybackBlocks[1] : null;

                        for (var blockIndex = 1; blockIndex <= maxBlockIndex; blockIndex++)
                        {
                            PlaybackBlocks[blockIndex].Index    = blockIndex;
                            PlaybackBlocks[blockIndex].Previous = PlaybackBlocks[blockIndex - 1];
                            PlaybackBlocks[blockIndex].Next     = blockIndex + 1 <= maxBlockIndex ? PlaybackBlocks[blockIndex + 1] : null;
                        }
                    }
                    else
                    {
                        targetBlock.Previous = maxBlockIndex >= 1 ? PlaybackBlocks[maxBlockIndex - 1] : null;
                        targetBlock.Next     = null;
                        targetBlock.Index    = PlaybackBlocks.Count - 1;

                        if (targetBlock.Previous != null)
                        {
                            targetBlock.Previous.Next = targetBlock;
                        }
                    }

                    // return the new target block
                    return(targetBlock);
                }
                catch { throw; }
                finally { UpdateCollectionProperties(); }
            }
        }
Exemple #6
0
 public PlexObject(MediaContainer m)
 {
     MediaContainer = m;
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="MediaComponent"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="streamIndex">Index of the stream.</param>
        /// <exception cref="ArgumentNullException">container</exception>
        /// <exception cref="MediaContainerException">The container exception.</exception>
        protected MediaComponent(MediaContainer container, int streamIndex)
        {
            // Ported from: https://github.com/FFmpeg/FFmpeg/blob/master/fftools/ffplay.c#L2559
            Container        = container ?? throw new ArgumentNullException(nameof(container));
            m_LoggingHandler = ((ILoggingSource)Container).LoggingHandler;
            m_CodecContext   = new IntPtr(ffmpeg.avcodec_alloc_context3(null));
            RC.Current.Add(CodecContext);
            StreamIndex = streamIndex;
            m_Stream    = new IntPtr(container.InputContext->streams[streamIndex]);
            StreamInfo  = container.MediaInfo.Streams[streamIndex];

            // Set default codec context options from probed stream
            var setCodecParamsResult = ffmpeg.avcodec_parameters_to_context(CodecContext, Stream->codecpar);

            if (setCodecParamsResult < 0)
            {
                this.LogWarning(Aspects.Component,
                                $"Could not set codec parameters. Error code: {setCodecParamsResult}");
            }

            // We set the packet timebase in the same timebase as the stream as opposed to the typical AV_TIME_BASE
            if (this is VideoComponent && Container.MediaOptions.VideoForcedFps > 0)
            {
                var fpsRational = ffmpeg.av_d2q(Container.MediaOptions.VideoForcedFps, 1000000);
                Stream->r_frame_rate       = fpsRational;
                CodecContext->pkt_timebase = new AVRational {
                    num = fpsRational.den, den = fpsRational.num
                };
            }
            else
            {
                CodecContext->pkt_timebase = Stream->time_base;
            }

            // Find the default decoder codec from the stream and set it.
            var      defaultCodec = ffmpeg.avcodec_find_decoder(Stream->codec->codec_id);
            AVCodec *forcedCodec  = null;

            // If set, change the codec to the forced codec.
            if (Container.MediaOptions.DecoderCodec.ContainsKey(StreamIndex) &&
                string.IsNullOrWhiteSpace(Container.MediaOptions.DecoderCodec[StreamIndex]) == false)
            {
                var forcedCodecName = Container.MediaOptions.DecoderCodec[StreamIndex];
                forcedCodec = ffmpeg.avcodec_find_decoder_by_name(forcedCodecName);
                if (forcedCodec == null)
                {
                    this.LogWarning(Aspects.Component,
                                    $"COMP {MediaType.ToString().ToUpperInvariant()}: " +
                                    $"Unable to set decoder codec to '{forcedCodecName}' on stream index {StreamIndex}");
                }
            }

            // Check we have a valid codec to open and process the stream.
            if (defaultCodec == null && forcedCodec == null)
            {
                var errorMessage = $"Fatal error. Unable to find suitable decoder for {Stream->codec->codec_id.ToString()}";
                CloseComponent();
                throw new MediaContainerException(errorMessage);
            }

            var      codecCandidates = new[] { forcedCodec, defaultCodec };
            AVCodec *selectedCodec   = null;
            var      codecOpenResult = 0;

            foreach (var codec in codecCandidates)
            {
                if (codec == null)
                {
                    continue;
                }

                // Pass default codec stuff to the codec context
                CodecContext->codec_id = codec->id;

                // Process the decoder options
                {
                    var decoderOptions = Container.MediaOptions.DecoderParams;

                    // Configure the codec context flags
                    if (decoderOptions.EnableFastDecoding)
                    {
                        CodecContext->flags2 |= ffmpeg.AV_CODEC_FLAG2_FAST;
                    }
                    if (decoderOptions.EnableLowDelayDecoding)
                    {
                        CodecContext->flags |= ffmpeg.AV_CODEC_FLAG_LOW_DELAY;
                    }

                    // process the low res option
                    if (decoderOptions.LowResolutionIndex != ResolutionDivider.Full && codec->max_lowres > 0)
                    {
                        var lowResOption = Math.Min((byte)decoderOptions.LowResolutionIndex, codec->max_lowres)
                                           .ToString(CultureInfo.InvariantCulture);
                        decoderOptions.LowResIndexOption = lowResOption;
                    }

                    // Ensure ref counted frames for audio and video decoding
                    if (CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO || CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_AUDIO)
                    {
                        decoderOptions.RefCountedFrames = "1";
                    }
                }

                // Setup additional settings. The most important one is Threads -- Setting it to 1 decoding is very slow. Setting it to auto
                // decoding is very fast in most scenarios.
                var codecOptions = Container.MediaOptions.DecoderParams.GetStreamCodecOptions(Stream->index);

                // Enable Hardware acceleration if requested
                (this as VideoComponent)?.AttachHardwareDevice(container.MediaOptions.VideoHardwareDevice);

                // Open the CodecContext. This requires exclusive FFmpeg access
                lock (CodecLock)
                {
                    var codecOptionsRef = codecOptions.Pointer;
                    codecOpenResult = ffmpeg.avcodec_open2(CodecContext, codec, &codecOptionsRef);
                    codecOptions.UpdateReference(codecOptionsRef);
                }

                // Check if the codec opened successfully
                if (codecOpenResult < 0)
                {
                    this.LogWarning(Aspects.Component,
                                    $"Unable to open codec '{FFInterop.PtrToStringUTF8(codec->name)}' on stream {streamIndex}");

                    continue;
                }

                // If there are any codec options left over from passing them, it means they were not consumed
                var currentEntry = codecOptions.First();
                while (currentEntry?.Key != null)
                {
                    this.LogWarning(Aspects.Component,
                                    $"Invalid codec option: '{currentEntry.Key}' for codec '{FFInterop.PtrToStringUTF8(codec->name)}', stream {streamIndex}");
                    currentEntry = codecOptions.Next(currentEntry);
                }

                selectedCodec = codec;
                break;
            }

            if (selectedCodec == null)
            {
                CloseComponent();
                throw new MediaContainerException($"Unable to find suitable decoder codec for stream {streamIndex}. Error code {codecOpenResult}");
            }

            // Startup done. Set some options.
            Stream->discard = AVDiscard.AVDISCARD_DEFAULT;
            MediaType       = (MediaType)CodecContext->codec_type;

            switch (MediaType)
            {
            case MediaType.Audio:
            case MediaType.Video:
                BufferCountThreshold    = 25;
                BufferDurationThreshold = TimeSpan.FromSeconds(1);
                DecodePacketFunction    = DecodeNextAVFrame;
                break;

            case MediaType.Subtitle:
                BufferCountThreshold    = 0;
                BufferDurationThreshold = TimeSpan.Zero;
                DecodePacketFunction    = DecodeNextAVSubtitle;
                break;

            default:
                throw new NotSupportedException($"A component of MediaType '{MediaType}' is not supported");
            }

            if (StreamInfo.IsAttachedPictureDisposition)
            {
                BufferCountThreshold    = 0;
                BufferDurationThreshold = TimeSpan.Zero;
            }

            // Compute the start time
            StartTime = Stream->start_time == ffmpeg.AV_NOPTS_VALUE ?
                        Container.MediaStartTime :
                        Stream->start_time.ToTimeSpan(Stream->time_base);

            // compute the duration
            Duration = (Stream->duration == ffmpeg.AV_NOPTS_VALUE || Stream->duration <= 0) ?
                       Container.MediaDuration :
                       Stream->duration.ToTimeSpan(Stream->time_base);

            CodecId   = Stream->codec->codec_id;
            CodecName = FFInterop.PtrToStringUTF8(selectedCodec->name);
            BitRate   = Stream->codec->bit_rate < 0 ? 0 : Stream->codec->bit_rate;
            this.LogDebug(Aspects.Component,
                          $"{MediaType.ToString().ToUpperInvariant()}: Start Offset: {StartTime.Format()}; Duration: {Duration.Format()}");

            // Begin processing with a flush packet
            SendFlushPacket();
        }
Exemple #8
0
        public static MediaContainer GetMediaInfo_New(string filename)
        {
            try
            {
                string exe  = GetMediaInfoPathForOS();
                string args = $"--OUTPUT=JSON \"{filename}\"";

                var pProcess = GetProcess(exe, args);
                pProcess.Start();
                string output = pProcess.StandardOutput.ReadToEnd().Trim();
                //Wait for process to finish
                pProcess.WaitForExit();

                if (pProcess.ExitCode != 0 || !output.StartsWith("{"))
                {
                    // We have an error
                    if (string.IsNullOrWhiteSpace(output) || output.EqualsInvariantIgnoreCase("null"))
                    {
                        output = pProcess.StandardError.ReadToEnd().Trim();
                    }

                    if (string.IsNullOrWhiteSpace(output) || output.EqualsInvariantIgnoreCase("null"))
                    {
                        output = "No message";
                    }

                    logger.Error($"MediaInfo threw an error on {filename}: {output}");
                    return(null);
                }

                var settings = new JsonSerializerSettings
                {
                    Converters = new JsonConverter[]
                    {
                        new StreamJsonConverter(), new BooleanConverter(), new StringEnumConverter(),
                        new DateTimeConverter()
                        {
                            DateTimeFormat = "yyyy-MM-dd HH:mm:ss"
                        }, new MultiIntConverter()
                    }
                };

                // assuming json, as it starts with {
                MediaContainer m = JsonConvert.DeserializeObject <MediaContainer>(output, settings);
                m.media.track.ForEach(a =>
                {
                    if (!string.IsNullOrEmpty(a.Language))
                    {
                        var langs = MediaInfoUtils.GetLanguageMapping(a.Language);
                        if (langs == null)
                        {
                            logger.Error($"{filename} had a missing language code: {a.Language}");
                            return;
                        }
                        a.LanguageCode = langs.Item1;
                        a.LanguageName = langs.Item2;
                    }
                });
                return(m);
            }
            catch (Exception e)
            {
                logger.Error($"MediaInfo threw an error on {filename}: {e}");
                return(null);
            }
        }
Exemple #9
0
 private static ICollection <Device> GetByProvides(MediaContainer container, string provides)
 {
     return(container.Devices.Where(d => d.Provides.Contains(provides))
            .OrderByDescending(d => d.LastSeenAt).ToList());
 }
        public async Task <Uri> GetMediaUri(string blobName, MediaContainer containerType)
        {
            var container = await GetBlobContainer(containerType);

            return(container.GetBlobClient(blobName).Uri);
        }
        public async Task <bool> Exists(string blobName, MediaContainer containerType)
        {
            var container = await GetBlobContainer(containerType);

            return(await container.ExistsAsync());
        }
Exemple #12
0
        public override void CalculateExpectedTestingTime(ICollection otherSubTests, ISubTestArgument arg)
        {
            // get the results from the prerequisite tests
            CdsResult_BrowseAll           BROWSE_RESULTS = null;
            CdsResult_GetSortCapabilities SORTCAPS       = null;

            foreach (ISubTest preTest in otherSubTests)
            {
                if (preTest.Name == this.PRE_BROWSEALL.Name)
                {
                    BROWSE_RESULTS = preTest.Details as CdsResult_BrowseAll;
                }
                else if (preTest.Name == this.PRE_SORTCAPS.Name)
                {
                    SORTCAPS = preTest.Details as CdsResult_GetSortCapabilities;
                }
            }

            if (BROWSE_RESULTS == null)
            {
                return;
            }

            if (SORTCAPS == null)
            {
                return;
            }

            if (BROWSE_RESULTS.LargestContainer == null)
            {
                return;
            }

            MediaContainer MC = BROWSE_RESULTS.LargestContainer as MediaContainer;

            if (MC == null)
            {
                return;
            }

            ArrayList sortFields = new ArrayList();

            if (SORTCAPS.SortCapabilities == "")
            {
            }
            else if (SORTCAPS.SortCapabilities == "*")
            {
                sortFields = (ArrayList)BROWSE_RESULTS.PropertyNames.Clone();
            }
            else
            {
                sortFields.AddRange(GetSortFields(SORTCAPS.SortCapabilities));
            }

            int   fieldCount = sortFields.Count;
            IList childList  = BROWSE_RESULTS.LargestContainer.CompleteList;
            uint  inc        = (uint)(childList.Count / 3);
            int   firstInc   = (fieldCount / 3);

            if (firstInc == 0)
            {
                firstInc = 1;
            }
            int totalBrowses = 0;

            for (int numFields = 0; numFields < fieldCount; numFields++)
            {
                for (int first = 0; first < fieldCount; first += firstInc)
                {
                    //for (uint i=0; i < childList.Count; i+=inc)
                    {
                        totalBrowses++;
                    }
                }
            }
            //add one for an unsorted browse
            totalBrowses++;
            //multiply by 2 because we have 2 rounds to check for consistency in ordered results
            totalBrowses *= 2;
            //calculate expected time
            this._ExpectedTestingTime = totalBrowses * 900;
        }
Exemple #13
0
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            CpContentDirectory CDS = this.GetCDS(arg._Device);

            _Details        = new CdsResult_BrowseSortCriteria();
            this._TestState = UPnPTestStates.Running;
            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" started.");

            // get the results from the prerequisite tests
            CdsResult_BrowseAll           BROWSE_RESULTS = null;
            CdsResult_GetSortCapabilities SORTCAPS       = null;

            try
            {
                foreach (ISubTest preTest in otherSubTests)
                {
                    if (preTest.Name == this.PRE_BROWSEALL.Name)
                    {
                        BROWSE_RESULTS = preTest.Details as CdsResult_BrowseAll;
                    }
                    else if (preTest.Name == this.PRE_SORTCAPS.Name)
                    {
                        SORTCAPS = preTest.Details as CdsResult_GetSortCapabilities;
                    }
                }

                if (BROWSE_RESULTS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }

                if (SORTCAPS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_SORTCAPS.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }
            }
            catch (Exception e)
            {
                throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" and \"" + this.PRE_SORTCAPS + "\" tests be run before. An error occurred when attempting to obtain the results of those prerequisites.", otherSubTests, e);
            }
            _Details.BrowseAllResults = BROWSE_RESULTS;
            _Details.SortCapsResults  = SORTCAPS;

            UPnPTestStates state = this._TestState;

            if (BROWSE_RESULTS.LargestContainer == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " failed to find the container with the most child objects. " + this._Name + " requires this value.", BROWSE_RESULTS);
            }

            MediaContainer MC = BROWSE_RESULTS.LargestContainer as MediaContainer;

            if (MC == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " has the largest container as type \"" + BROWSE_RESULTS.LargestContainer.GetType().ToString() + "\" when \"" + this.Name + "\" requires \"" + typeof(MediaContainer).ToString() + "\".", BROWSE_RESULTS);
            }


            ArrayList sortFields = new ArrayList();

            if (SORTCAPS.SortCapabilities == "")
            {
                //arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name+"\" has no sorting capabilities.");
            }
            else if (SORTCAPS.SortCapabilities == "*")
            {
                sortFields = (ArrayList)BROWSE_RESULTS.PropertyNames.Clone();
            }
            else
            {
                sortFields.AddRange(GetSortFields(SORTCAPS.SortCapabilities));
            }

            _Details.ExpectedTotalBrowseRequests = 0;
            _Details.SortFields = sortFields;
            int   fieldCount = sortFields.Count;
            IList childList  = BROWSE_RESULTS.LargestContainer.CompleteList;

            _Details.ExpectedTotalBrowseRequests = 0;            //fieldCount * fieldCount * fieldCount;
            uint inc      = (uint)(childList.Count / 3);
            int  firstInc = (fieldCount / 3);

            if (firstInc == 0)
            {
                firstInc = 1;
            }
            for (int numFields = 0; numFields < fieldCount; numFields++)
            {
                for (int first = 0; first < fieldCount; first += firstInc)
                {
                    //for (uint i=0; i < childList.Count; i+=inc)
                    {
                        _Details.ExpectedTotalBrowseRequests++;
                    }
                }
            }
            // add 1 for an unsorted browse
            _Details.ExpectedTotalBrowseRequests++;
            //multiply by 2 because we have 2 rounds to check for consistency in ordered results
            _Details.ExpectedTotalBrowseRequests *= 2;

            //calculate time
            this._ExpectedTestingTime = _Details.ExpectedTotalBrowseRequests * 900;
            arg.ActiveTests.UpdateTimeAndProgress(0);

            if (state <= UPnPTestStates.Running)
            {
                state = UPnPTestStates.Pass;
                try
                {
                    ArrayList round2 = new ArrayList();

                    //perform the standard unsorted browse
                    BrowseInput input = new BrowseInput();
                    input.BrowseFlag     = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN;
                    input.StartingIndex  = 0;
                    input.ObjectID       = MC.ID;
                    input.RequestedCount = 0;
                    input.Filter         = "*";
                    input.SortCriteria   = "";

                    CdsBrowseSearchResults br = Browse(input, this, arg, CDS, _Details);
                    Round2 r2 = new Round2();
                    r2.Input          = (BrowseInput)input.Clone();
                    r2.PreviousResult = br;
                    round2.Add(r2);

                    for (int numFields = 0; numFields < fieldCount; numFields++)
                    {
                        for (int first = 0; first < fieldCount; first += firstInc)
                        {
                            ArrayList sortSettings = GetSortSettings(sortFields, first, first);
                            input.SortCriteria = GetSortCriteriaString(sortSettings, numFields + first);
                            arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900);

                            uint ignored;

                            //use this sorter for to determine the expected order of the media objects
                            IMediaSorter sorter         = new MediaSorter(true, input.SortCriteria);
                            IList        expectedSorted = MC.BrowseSorted(0, 0, sorter, out ignored);

                            br = Browse(input, this, arg, CDS, _Details);
                            arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900);

                            this.CompareResultsAgainstExpected(br, expectedSorted, ref state, arg, input, false);

                            r2                = new Round2();
                            r2.Input          = (BrowseInput)input.Clone();
                            r2.PreviousResult = br;
                            round2.Add(r2);
                        }
                    }

                    //do round2 - check for consistency in results
                    foreach (Round2 r in round2)
                    {
                        br = Browse(r.Input, this, arg, CDS, _Details);
                        arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900);
                        this.CompareResultsAgainstExpected(br, r.PreviousResult.MediaObjects, ref state, arg, r.Input, true);
                    }
                }
                catch (TerminateEarly te)
                {
                    string reason = "\"" + this.Name + "\" terminating early. Reason => " + te.Message;
                    arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, reason);

                    state = UPnPTestStates.Failed;
                }
            }


            // finish up logging
            this._TestState = state;

            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("\"{0}\" completed", this.Name);

            if (this._TestState <= UPnPTestStates.Running)
            {
                throw new TestException("\"" + this.Name + "\" must have a pass/warn/fail result.", this._TestState);
            }

            switch (this._TestState)
            {
            case UPnPTestStates.Pass:
                sb.Append(" successfully.");
                break;

            case UPnPTestStates.Warn:
                sb.Append(" with warnings.");
                break;

            case UPnPTestStates.Failed:
                sb.Append(" with a failed result.");
                break;
            }

            arg._TestGroup.AddResult(sb.ToString());

            if (this._TestState <= UPnPTestStates.Warn)
            {
                if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests)
                {
                    throw new TestException("TotalBrowseRequests=" + _Details.TotalBrowseRequests.ToString() + " ExpectedTotal=" + _Details.ExpectedTotalBrowseRequests.ToString(), _Details);
                }
            }

            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, sb.ToString());

            return(this._TestState);
        }
Exemple #14
0
 public KodiObject(MediaContainer m)
 {
     MediaContainer = m;
 }
 public BaseObject(MediaContainer m)
 {
     MediaContainer = m;
 }
        /// <summary>
        /// Opens the specified media Asynchronously
        /// </summary>
        /// <param name="uri">The URI.</param>
        /// <returns></returns>
        private async Task OpenAsync(Uri uri)
        {
            try
            {
                await Task.Run(() =>
                {
                    var mediaUrl = uri.IsFile ? uri.LocalPath : uri.ToString();

                    Container = new MediaContainer(mediaUrl);
                    RaiseMediaOpeningEvent();
                    Container.Log(MediaLogMessageType.Debug, $"{nameof(OpenAsync)}: Entered");
                    Container.Initialize();
                });

                foreach (var t in Container.Components.MediaTypes)
                {
                    Blocks[t]         = new MediaBlockBuffer(MaxBlocks[t], t);
                    Frames[t]         = new MediaFrameQueue();
                    LastRenderTime[t] = TimeSpan.MinValue;
                    Renderers[t]      = CreateRenderer(t);
                }

                IsTaskCancellationPending = false;

                BlockRenderingCycle.Set();
                FrameDecodingCycle.Set();
                PacketReadingCycle.Set();

                PacketReadingTask = new Thread(RunPacketReadingWorker)
                {
                    IsBackground = true
                };
                FrameDecodingTask = new Thread(RunFrameDecodingWorker)
                {
                    IsBackground = true
                };
                BlockRenderingTask = new Thread(RunBlockRenderingWorker)
                {
                    IsBackground = true
                };

                PacketReadingTask.Start();
                FrameDecodingTask.Start();
                BlockRenderingTask.Start();

                RaiseMediaOpenedEvent();

                if (LoadedBehavior == MediaState.Play)
                {
                    Play();
                }
            }
            catch (Exception ex)
            {
                RaiseMediaFailedEvent(ex);
            }
            finally
            {
                UpdateMediaProperties();
                Container.Log(MediaLogMessageType.Debug, $"{nameof(OpenAsync)}: Completed");
            }
        }
Exemple #17
0
        public async Task CreateGraphMediaItem(MediaContainer mediaContainer, string userId)
        {
            string query = string.Format("g.addV('MediaItem').property('id', '{0}').property('OwnerId', {1}).property('UserId', {2})", mediaContainer.Id, mediaContainer.User.Id, userId);

            await ExecuteGraphQuery(query);
        }
        public async Task CloseAsync()
        {
            Container?.Log(MediaLogMessageType.Debug, $"{nameof(CloseAsync)}: Entered");
            Clock.Pause();

            IsTaskCancellationPending = true;

            // Wait for cycles to complete.
            await Task.Run(() =>
            {
                while (!BlockRenderingCycle.Wait(1))
                {
                }
                while (!FrameDecodingCycle.Wait(1))
                {
                }
                while (!PacketReadingCycle.Wait(1))
                {
                }
            });

            BlockRenderingTask?.Join();
            FrameDecodingTask?.Join();
            PacketReadingTask?.Join();

            BlockRenderingTask = null;
            FrameDecodingTask  = null;
            PacketReadingTask  = null;

            foreach (var renderer in Renderers.Values)
            {
                renderer.Close();
            }

            Renderers.Clear();

            // Reset the clock
            Clock.Reset();

            Container?.Log(MediaLogMessageType.Debug, $"{nameof(CloseAsync)}: Completed");

            // Dispose the container
            if (Container != null)
            {
                Container.Dispose();
                Container = null;
            }

            // Dispose the Blocks for all components
            foreach (var kvp in Blocks)
            {
                kvp.Value.Dispose();
            }
            Blocks.Clear();

            // Dispose the Frames for all components
            foreach (var kvp in Frames)
            {
                kvp.Value.Dispose();
            }
            Frames.Clear();

            // Clear the render times
            LastRenderTime.Clear();

            // Update notification properties
            UpdateMediaProperties();
            MediaState = MediaState.Close;
        }
 internal static MediaBlockBuffer Main(this MediaTypeDictionary <MediaBlockBuffer> blocks, MediaContainer container) =>
 blocks[container.Components?.MainMediaType ?? MediaType.None];
 /// <summary>
 /// Initializes a new instance of the <see cref="SubtitleComponent"/> class.
 /// </summary>
 /// <param name="container">The container.</param>
 /// <param name="streamIndex">Index of the stream.</param>
 internal SubtitleComponent(MediaContainer container, int streamIndex)
     : base(container, streamIndex)
 {
     // Adjust the offset according to options
     Delay = container.MediaOptions.SubtitlesDelay;
 }
 private static ICollection<Device> GetByProvides(MediaContainer container, string provides)
 {
     return container.Devices.Where(d => d.Provides.Contains(provides))
         .OrderByDescending(d => d.LastSeenAt).ToList();
 }
Exemple #22
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MediaComponent"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="streamIndex">Index of the stream.</param>
        /// <exception cref="ArgumentNullException">container</exception>
        /// <exception cref="MediaContainerException">The container exception.</exception>
        protected MediaComponent(MediaContainer container, int streamIndex)
        {
            Container    = container ?? throw new ArgumentNullException(nameof(container));
            CodecContext = ffmpeg.avcodec_alloc_context3(null);
            RC.Current.Add(CodecContext, $"134: {nameof(MediaComponent)}[{MediaType}].ctor()");
            StreamIndex = streamIndex;
            Stream      = container.InputContext->streams[StreamIndex];
            StreamInfo  = container.MediaInfo.Streams[StreamIndex];

            // Set codec options
            var setCodecParamsResult = ffmpeg.avcodec_parameters_to_context(CodecContext, Stream->codecpar);

            if (setCodecParamsResult < 0)
            {
                Container.Logger?.Log(MediaLogMessageType.Warning, $"Could not set codec parameters. Error code: {setCodecParamsResult}");
            }

            // We set the packet timebase in the same timebase as the stream as opposed to the tpyical AV_TIME_BASE
            ffmpeg.av_codec_set_pkt_timebase(CodecContext, Stream->time_base);

            // Find the codec and set it.
            var codec = ffmpeg.avcodec_find_decoder(Stream->codec->codec_id);

            if (codec == null)
            {
                var errorMessage = $"Fatal error. Unable to find suitable decoder for {Stream->codec->codec_id.ToString()}";
                CloseComponent();
                throw new MediaContainerException(errorMessage);
            }

            CodecContext->codec_id = codec->id;

            // Process the low res index option
            var lowResIndex = ffmpeg.av_codec_get_max_lowres(codec);

            if (Container.MediaOptions.EnableLowRes)
            {
                ffmpeg.av_codec_set_lowres(CodecContext, lowResIndex);
                CodecContext->flags |= ffmpeg.CODEC_FLAG_EMU_EDGE;
            }
            else
            {
                lowResIndex = 0;
            }

            // Configure the codec context flags
            if (Container.MediaOptions.EnableFastDecoding)
            {
                CodecContext->flags2 |= ffmpeg.AV_CODEC_FLAG2_FAST;
            }
            if ((codec->capabilities & ffmpeg.AV_CODEC_CAP_DR1) != 0)
            {
                CodecContext->flags |= ffmpeg.CODEC_FLAG_EMU_EDGE;
            }
            if ((codec->capabilities & ffmpeg.AV_CODEC_CAP_TRUNCATED) != 0)
            {
                CodecContext->flags |= ffmpeg.AV_CODEC_CAP_TRUNCATED;
            }
            if ((codec->capabilities & ffmpeg.CODEC_FLAG2_CHUNKS) != 0)
            {
                CodecContext->flags |= ffmpeg.CODEC_FLAG2_CHUNKS;
            }

            // Setup additional settings. The most important one is Threads -- Setting it to 1 decoding is very slow. Setting it to auto
            // decoding is very fast in most scenarios.
            var codecOptions = Container.MediaOptions.CodecOptions.FilterOptions(CodecContext->codec_id, Container.InputContext, Stream, codec);

            if (codecOptions.HasKey(Constants.CodecOptionThreads) == false)
            {
                codecOptions[Constants.CodecOptionThreads] =
                    Constants.EnableFFmpegLockManager ? "auto" : "1";
            }

            if (lowResIndex != 0)
            {
                codecOptions[Constants.CodecOptionLowRes] = lowResIndex.ToString(CultureInfo.InvariantCulture);
            }
            if (CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO || CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_AUDIO)
            {
                codecOptions[Constants.CodecOptionRefCountedFrames] = 1.ToString(CultureInfo.InvariantCulture);
            }

            // Enable Hardware acceleration if requested
            if (this is VideoComponent && container.MediaOptions.EnableHardwareAcceleration)
            {
                HardwareAccelerator.Dxva2.AttachDevice(this as VideoComponent);
            }

            // Open the CodecContext
            var codecOpenResult = 0;

            fixed(AVDictionary **reference = &codecOptions.Pointer)
            codecOpenResult = ffmpeg.avcodec_open2(CodecContext, codec, reference);

            if (codecOpenResult < 0)
            {
                CloseComponent();
                throw new MediaContainerException($"Unable to open codec. Error code {codecOpenResult}");
            }

            // If there are any codec options left over from passing them, it means they were not consumed
            if (codecOptions.First() != null)
            {
                Container.Logger?.Log(MediaLogMessageType.Warning, $"Codec Option '{codecOptions.First().Key}' not found.");
            }

            // Startup done. Set some options.
            Stream->discard = AVDiscard.AVDISCARD_DEFAULT;
            MediaType       = (MediaType)CodecContext->codec_type;

            // Compute the start time
            if (Stream->start_time == FFmpegEx.AV_NOPTS)
            {
                StartTimeOffset = Container.MediaStartTimeOffset;
            }
            else
            {
                StartTimeOffset = Stream->start_time.ToTimeSpan(Stream->time_base);
            }

            // compute the duration
            if (Stream->duration == FFmpegEx.AV_NOPTS || Stream->duration == 0)
            {
                Duration = Container.InputContext->duration.ToTimeSpan();
            }
            else
            {
                Duration = Stream->duration.ToTimeSpan(Stream->time_base);
            }

            CodecId   = Stream->codec->codec_id;
            CodecName = ffmpeg.avcodec_get_name(CodecId);
            Bitrate   = (int)Stream->codec->bit_rate;
            Container.Logger?.Log(MediaLogMessageType.Debug,
                                  $"COMP {MediaType.ToString().ToUpperInvariant()}: Start Offset: {StartTimeOffset.Format()}; Duration: {Duration.Format()}");
        }
Exemple #23
0
 public Artist(MediaContainer parent, dynamic dynMediaContainer)
 {
     this.Parent = parent;
     this.PopulateBaseMediaContainerProperties(dynMediaContainer);
 }
Exemple #24
0
 public Result Delete(MediaContainer item)
 {
     throw new NotImplementedException();
 }