public VideoPacket?GetNearestStreamDataLessThanEqual(PopTimeline.TimeUnit Time) { var Blocks = this.Blocks; if (Blocks.Count == 0) { return(null); } System.Func <int, VideoPacket> GetAt = (Index) => { return(Blocks[Index]); }; System.Func <VideoPacket, BinaryChop.CompareDirection> Compare = (OtherBlock) => { return(OtherBlock.GetTimeDirection(Time)); }; int?Match; int?Nearest; BinaryChop.Search(0, Blocks.Count - 1, GetAt, Compare, out Nearest, out Match); // nothing at/before this time if (Nearest.Value < 0) { return(null); } return(GetAt(Nearest.Value)); }
public override void GetTimeRange(out PopTimeline.TimeUnit Min, out PopTimeline.TimeUnit Max) { int?MinTime = null; int?MaxTime = null; Pop.AllocIfNull(ref VideoStreams); foreach (var bs in VideoStreams) { var Blocks = bs.Blocks; if (Blocks == null || Blocks.Count == 0) { continue; } var bsmin = Blocks[0].GetStartTime().Time; var bsmax = Blocks[Blocks.Count - 1].GetEndTime().Time; MinTime = MinTime.HasValue ? Mathf.Min(MinTime.Value, bsmin) : bsmin; MaxTime = MaxTime.HasValue ? Mathf.Max(MaxTime.Value, bsmax) : bsmax; } if (!MinTime.HasValue) { throw new System.Exception("No time range (no data)"); } Min = new PopTimeline.TimeUnit(MinTime.Value); Max = new PopTimeline.TimeUnit(MaxTime.Value); }
// is this time before,inside,or after this block public BinaryChop.CompareDirection GetTimeDirection(PopTimeline.TimeUnit Time) { if (Time.Time < StartTimeMs) { return(BinaryChop.CompareDirection.Before); } if (Time.Time > StartTimeMs + DurationMs) { return(BinaryChop.CompareDirection.After); } return(BinaryChop.CompareDirection.Inside); }
public VideoPacket?GetStreamData(PopTimeline.TimeUnit Time) { int?Index; int?NearestIndex; GetStreamDataIndex(Time, out Index, out NearestIndex); if (!Index.HasValue) { return(null); } return(Blocks[Index.Value]); }
void GetStreamDataIndex(PopTimeline.TimeUnit Time, out int?Match, out int?Nearest) { var Blocks = this.Blocks; if (Blocks.Count == 0) { Match = null; Nearest = null; return; } System.Func <int, VideoPacket> GetAt = (Index) => { return(Blocks[Index]); }; System.Func <VideoPacket, BinaryChop.CompareDirection> Compare = (OtherBlock) => { return(OtherBlock.GetTimeDirection(Time)); }; BinaryChop.Search(0, Blocks.Count - 1, GetAt, Compare, out Nearest, out Match); }
void OnTimeSelected(PopTimeline.TimeUnit SelectedTime) { // find keyframe closest to time var VideoStream = Sink.GetVideoStream(VideoStreamName); var Packet = VideoStream.GetNearestStreamDataLessThanEqual(SelectedTime); // todo: avoid infinite loop properly var InfLoopCheck = 1000; while (Packet.HasValue && --InfLoopCheck > 0) { if (Packet.Value.Sample.IsKeyframe) { break; } // look for previous var PrevTime = new PopTimeline.TimeUnit(Packet.Value.GetStartTime().Time - 1); Packet = VideoStream.GetNearestStreamDataLessThanEqual(PrevTime); } if (InfLoopCheck <= 0) { Packet = null; } if (Packet == null) { throw new System.Exception("Failed to find keyframe before " + SelectedTime); } var HeaderData = VideoStream.TrackMeta.SampleDescriptions[0].Data; var PacketData = Sink.GetFileData(Packet.Value.Sample.DataPosition, Packet.Value.Sample.DataSize); // just h264 current expects annexb format. Mp4 is probably in AVCC (see meta!) HeaderData = PopX.H264.GetH264AnnexB(HeaderData); PacketData = PopX.H264.GetH264AnnexB(PacketData); OnH264Data.Invoke(HeaderData, PacketData); }
public VideoPacket?GetNearestStreamDataGreaterThanEqual(PopTimeline.TimeUnit Time) { var Blocks = this.Blocks; if (Blocks.Count == 0) { return(null); } System.Func <int, VideoPacket> GetAt = (Index) => { return(Blocks[Index]); }; System.Func <VideoPacket, BinaryChop.CompareDirection> Compare = (OtherBlock) => { return(OtherBlock.GetTimeDirection(Time)); }; int?Match; int?Nearest; BinaryChop.Search(0, Blocks.Count - 1, GetAt, Compare, out Nearest, out Match); if (Match.HasValue) { return(GetAt(Match.Value)); } // next must the one after prev var Next = Nearest.Value + 1; if (Next >= Blocks.Count) { return(null); } return(GetAt(Next)); }
public override PopTimeline.StreamDataItem GetNearestOrNextStreamData(PopTimeline.DataStreamMeta _StreamMeta, ref PopTimeline.TimeUnit Time) { var StreamMeta = (VideoStreamMeta)_StreamMeta; var BlockStream = VideoStreams[StreamMeta.StreamIndex]; var NextData = BlockStream.GetNearestStreamDataGreaterThanEqual(Time); var Next = NextData.Value; Time = Next.GetStartTime(); return(Next); }
public override PopTimeline.StreamDataItem GetNearestOrPrevStreamData(PopTimeline.DataStreamMeta _StreamMeta, ref PopTimeline.TimeUnit Time) { var StreamMeta = (VideoStreamMeta)_StreamMeta; var BlockStream = VideoStreams[StreamMeta.StreamIndex]; var PrevData = BlockStream.GetNearestStreamDataLessThanEqual(Time); var Prev = PrevData.Value; Time = Prev.GetStartTime(); return(Prev); }
public override List <PopTimeline.StreamDataItem> GetStreamData(PopTimeline.DataStreamMeta _StreamMeta, PopTimeline.TimeUnit MinTime, PopTimeline.TimeUnit MaxTime) { var StreamMeta = (VideoStreamMeta)_StreamMeta; var BlockStream = VideoStreams[StreamMeta.StreamIndex]; var Data = new List <PopTimeline.StreamDataItem>(); var Blocks = BlockStream.Blocks; if (Blocks.Count == 0) { return(Data); } // find start with binary chop. // find TAIL and work backwards as nearestprev will be last time, but if we do min we can start out of range System.Func <int, VideoPacket> GetAt = (Index) => { return(Blocks[Index]); }; System.Func <VideoPacket, BinaryChop.CompareDirection> Compare = (OtherBlock) => { return(OtherBlock.GetTimeDirection(MaxTime)); }; int?MaxMatch; int?MaxNearestPrev; BinaryChop.Search(0, Blocks.Count - 1, GetAt, Compare, out MaxNearestPrev, out MaxMatch); int Last = MaxNearestPrev.Value; // go earlier for (int b = Last; b >= 0; b--) { var Block = Blocks[b]; var CompareDir = Block.GetTimeDirection(MinTime); // if min time is AFTER block, block is before min if (CompareDir == BinaryChop.CompareDirection.After) { break; } Data.Insert(0, Block); } return(Data); }