示例#1
0
        public void Reset_CalledWhileFlushIsInProgress_CancelsFlush()
        {
            AsyncContext.Run(async() =>
            {
                var demuxerStub = Substitute.For <IDemuxer>();
                demuxerStub.Completion.Returns(Task.Delay(-1));

                using (var controller = new DemuxerController(demuxerStub))
                {
                    var flushTask = controller.Flush();

                    controller.Reset();

                    try
                    {
                        await flushTask;
                        Assert.Fail();
                    }
                    catch (TaskCanceledException)
                    {
                        // ignored
                    }
                    catch (OperationCanceledException)
                    {
                        // ignored
                    }
                }
            });
        }
示例#2
0
        public void Start_PacketsDemuxed_PublishesPackets(StartType startType)
        {
            AsyncContext.Run(async() =>
            {
                var demuxerStub = Substitute.For <IDemuxer>();
                var packet      = new Packet {
                    StreamType = StreamType.Video, IsEOS = false, IsKeyFrame = true
                };
                demuxerStub.NextPacket().Returns(Task.FromResult(packet));
                demuxerStub.IsInitialized().Returns(true);
                demuxerStub.Completion.Returns(Task.Delay(500));

                using (var controller = new DemuxerController(demuxerStub))
                {
                    var packetReadyTask = controller.PacketReady()
                                          .Take(2)
                                          .Count()
                                          .FirstAsync()
                                          .ToTask();

                    StartController(controller, startType);

                    var receivedCount = await packetReadyTask;
                    Assert.That(receivedCount, Is.EqualTo(2));
                }
            });
        }
示例#3
0
        public void Start_DRMInitDataFound_PublishesDRMInitData(StartType startType)
        {
            AsyncContext.Run(async() =>
            {
                var initData = new DRMInitData
                {
                    StreamType = StreamType.Video,
                    InitData   = new byte[1]
                };
                var demuxerStub = CreateDemuxerStub(new ClipConfiguration
                {
                    DrmInitDatas = new List <DRMInitData> {
                        initData
                    }
                }, startType);

                using (var controller = new DemuxerController(demuxerStub))
                {
                    var initDataTask = controller.DrmInitDataFound().FirstAsync().ToTask();

                    StartController(controller, startType);

                    var receivedInitData = await initDataTask;
                    Assert.That(receivedInitData, Is.EqualTo(initData));
                }
            });
        }
示例#4
0
        private static DashMediaPipeline CreateMediaPipeline(StreamType streamType)
        {
            var throughputHistory = new ThroughputHistory();
            var dashClient        = new DashClient(throughputHistory, streamType);
            var controller        = new DemuxerController(new FFmpegDemuxer(new FFmpegGlue()));

            controller.SetDataSource(dashClient.ChunkReady());

            return(new DashMediaPipeline(dashClient, controller, throughputHistory, streamType));
        }
示例#5
0
        private static IDemuxerController CreateDemuxerController(IObservable <byte[]> chunkReady = null)
        {
            var demuxer    = new FFmpegDemuxer(new FFmpegGlue());
            var controller = new DemuxerController(demuxer);

            if (chunkReady != null)
            {
                controller.SetDataSource(chunkReady);
            }
            return(controller);
        }
示例#6
0
        public void Reset_Called_ResetsDemuxer()
        {
            var demuxerMock = Substitute.For <IDemuxer>();

            using (var controller = new DemuxerController(demuxerMock))
            {
                controller.Reset();

                demuxerMock.Received().Reset();
            }
        }
示例#7
0
        public void Flush_Called_ResetsDemuxer()
        {
            AsyncContext.Run(async() =>
            {
                var demuxerMock = Substitute.For <IDemuxer>();
                using (var controller = new DemuxerController(demuxerMock))
                {
                    await controller.Flush();

                    demuxerMock.Received().Reset();
                }
            });
        }
示例#8
0
        public void Seek_CalledWhenPaused_DoesntDemuxNextPacket()
        {
            AsyncContext.Run(async() =>
            {
                var demuxerMock = Substitute.For <IDemuxer>();
                demuxerMock.IsInitialized().Returns(true);

                using (var controller = new DemuxerController(demuxerMock))
                {
                    controller.Pause();
                    await controller.Seek(TimeSpan.FromSeconds(5), CancellationToken.None);
                    await demuxerMock.DidNotReceive().NextPacket();
                }
            });
        }
示例#9
0
        public void Flush_CalledWhileChunkIsPending_ChunkIsDeliveredToDemuxer()
        {
            AsyncContext.Run(async() => {
                var demuxerMock = Substitute.For <IDemuxer>();
                using (var controller = new DemuxerController(demuxerMock))
                {
                    var subject = new Subject <byte[]>();
                    controller.SetDataSource(subject.AsObservable());
                    subject.OnNext(new byte[0]);

                    demuxerMock.When(demuxer => demuxer.Complete())
                    .Do(_ => demuxerMock.Received().PushChunk(Arg.Any <byte[]>()));

                    await controller.Flush();
                }
            });
        }
示例#10
0
        public IDataProvider Create(ClipDefinition clip)
        {
            if (clip == null)
            {
                throw new ArgumentNullException(nameof(clip), "clip cannot be null");
            }

            if (!SupportsClip(clip))
            {
                throw new ArgumentException("unsupported clip type");
            }

            var demuxer           = new FFmpegDemuxer(new FFmpegGlue());
            var demuxerController = new DemuxerController(demuxer);

            return(new HLSDataProvider(demuxerController, clip));
        }
示例#11
0
        public void Start_DemuxerInitFails_PublishesDemuxerError(StartType startType)
        {
            AsyncContext.Run(async() =>
            {
                var demuxerStub = CreateFailingDemuxerStub(startType);
                using (var controller = new DemuxerController(demuxerStub))
                {
                    var demuxerErrorTask = controller.DemuxerError().FirstAsync().ToTask();

                    StartController(controller, startType);

                    var error = await demuxerErrorTask;

                    Assert.That(error, Is.Not.Null);
                }
            });
        }
示例#12
0
        public void Reset_CalledWhileDataSourcePublishedChunk_SkipsPublishedChunk()
        {
            AsyncContext.Run(async() => {
                var demuxerMock = Substitute.For <IDemuxer>();

                using (var dataSource = new Subject <byte[]>())
                    using (var controller = new DemuxerController(demuxerMock))
                    {
                        controller.SetDataSource(dataSource);

                        dataSource.OnNext(new byte[1]);
                        controller.Reset();
                        await Task.Yield();

                        demuxerMock.DidNotReceive().PushChunk(Arg.Any <byte[]>());
                    }
            });
        }
示例#13
0
        public void Pause_Called_DoesntRetrieveNextPacket(StartType startType)
        {
            AsyncContext.Run(async() =>
            {
                var demuxerMock = Substitute.For <IDemuxer>();
                demuxerMock.IsInitialized().Returns(true);

                using (var controller = new DemuxerController(demuxerMock))
                {
                    StartController(controller, startType);

                    controller.Pause();

                    await Task.Yield();

                    await demuxerMock.DidNotReceive().NextPacket();
                }
            });
        }
示例#14
0
        public void Seek_Called_ListensForEos()
        {
            AsyncContext.Run(async() =>
            {
                var demuxerStub = Substitute.For <IDemuxer>();
                demuxerStub.NextPacket().Returns(Utils.TaskExtensions.Never <Packet>());
                demuxerStub.Completion.Returns(Task.CompletedTask);

                using (var controller = new DemuxerController(demuxerStub))
                {
                    var packetReady = controller.PacketReady().FirstAsync().ToTask();

                    await controller.Seek(TimeSpan.FromSeconds(5), CancellationToken.None);

                    var packet = await packetReady;
                    Assert.That(packet, Is.Null);
                }
            });
        }
        public IDataProvider Create(ClipDefinition clip)
        {
            if (clip == null)
            {
                throw new ArgumentNullException(nameof(clip), "clip cannot be null");
            }

            if (!SupportsClip(clip))
            {
                throw new ArgumentException("unsupported clip type");
            }

            var rtspClient        = new RTSPClient();
            var demuxer           = new FFmpegDemuxer(new FFmpegGlue());
            var demuxerController = new DemuxerController(demuxer);

            demuxerController.SetDataSource(rtspClient.ChunkReady());

            return(new RTSPDataProvider(demuxerController, rtspClient, clip));
        }
示例#16
0
        public void Start_ClipDurationFound_PublishesClipDuration(StartType startType)
        {
            AsyncContext.Run(async() =>
            {
                var expectedDuration = TimeSpan.FromSeconds(10);
                var demuxerStub      = CreateDemuxerStub(new ClipConfiguration {
                    Duration = expectedDuration
                }, startType);

                using (var controller = new DemuxerController(demuxerStub))
                {
                    var clipDurationTask = controller.ClipDurationFound().FirstAsync().ToTask();

                    StartController(controller, startType);

                    var duration = await clipDurationTask;
                    Assert.That(duration, Is.EqualTo(expectedDuration));
                }
            });
        }
示例#17
0
        public void SetDataSource_DataSourceCompletes_SignalsEos()
        {
            AsyncContext.Run(async() =>
            {
                var demuxerStub = Substitute.For <IDemuxer>();
                var dataSource  = new Subject <byte[]>();
                using (var controller = new DemuxerController(demuxerStub))
                {
                    controller.SetDataSource(dataSource);
                    var packetReadyTask = controller.PacketReady()
                                          .FirstAsync()
                                          .ToTask();

                    dataSource.OnNext(null);

                    var isEmpty = await packetReadyTask;
                    Assert.That(isEmpty, Is.Null);
                }
            });
        }
示例#18
0
        public void Start_StreamConfigFound_PublishesStreamConfig(StartType startType)
        {
            AsyncContext.Run(async() =>
            {
                var videoConfig = new VideoStreamConfig();
                var demuxerStub = CreateDemuxerStub(new ClipConfiguration
                {
                    StreamConfigs = new List <StreamConfig> {
                        videoConfig
                    }
                }, startType);

                using (var controller = new DemuxerController(demuxerStub))
                {
                    var streamConfigTask = controller.StreamConfigReady().FirstAsync().ToTask();

                    StartController(controller, startType);

                    var receivedConfig = await streamConfigTask;
                    Assert.That(receivedConfig, Is.EqualTo(videoConfig));
                }
            });
        }
示例#19
0
        public void Reset_Called_NextPacketNotCalledAfter(StartType startType)
        {
            AsyncContext.Run(async() =>
            {
                var demuxerMock = Substitute.For <IDemuxer>();
                var tcs         = new TaskCompletionSource <Packet>();
                demuxerMock.NextPacket().Returns(tcs.Task);
                demuxerMock.IsInitialized().Returns(true);

                using (var controller = new DemuxerController(demuxerMock))
                {
                    StartController(controller, startType);
                    await Task.Yield(); // Demuxer.InitFor completes, first Demuxer.NextPacket is called

                    controller.Reset();
                    tcs.SetResult(new Packet());

                    await Task.Yield(); // first Demuxer.NextPacket completes and another Demuxer.NextPacket is
                                        // not called
                    await demuxerMock.Received(1).NextPacket();
                }
            });
        }