/// <summary> /// Tries to add an entry created from the frame. /// </summary> /// <param name="managedFrame">The managed frame.</param> /// <returns> /// True if the index entry was created from the frame. /// False if the frame is of wrong picture type or if it already existed. /// </returns> public bool TryAdd(VideoFrame managedFrame) { // Update the Seek index if (managedFrame.PictureType != AVPictureType.AV_PICTURE_TYPE_I) { return(false); } // Create the seek entry var seekEntry = new VideoSeekIndexEntry(managedFrame); // Check if the entry already exists. if (Entries.BinarySearch(seekEntry, LookupComparer) >= 0) { return(false); } // Add the seek entry and ensure they are sorted. Entries.Add(seekEntry); Entries.Sort(LookupComparer); return(true); }
/// <summary> /// Adds the monotonic entries up to a stream duration. /// </summary> /// <param name="streamDuration">Duration of the stream.</param> public void AddMonotonicEntries(TimeSpan streamDuration) { if (Entries.Count < 2) { return; } while (true) { var lastEntry = Entries[Entries.Count - 1]; var prevEntry = Entries[Entries.Count - 2]; var presentationTime = lastEntry.PresentationTime == ffmpeg.AV_NOPTS_VALUE ? ffmpeg.AV_NOPTS_VALUE : lastEntry.PresentationTime + (lastEntry.PresentationTime - prevEntry.PresentationTime); var decodingTime = lastEntry.DecodingTime == ffmpeg.AV_NOPTS_VALUE ? ffmpeg.AV_NOPTS_VALUE : lastEntry.DecodingTime + (lastEntry.DecodingTime - prevEntry.DecodingTime); var startTimeTicks = lastEntry.StartTime.Ticks + (lastEntry.StartTime.Ticks - prevEntry.StartTime.Ticks); var entry = new VideoSeekIndexEntry( lastEntry.StreamIndex, lastEntry.StreamTimeBase.num, lastEntry.StreamTimeBase.den, startTimeTicks, presentationTime, decodingTime); if (entry.StartTime.Ticks > streamDuration.Ticks) { return; } Entries.Add(entry); } }
/// <summary> /// Loads the specified stream in the CSV-like UTF8 format it was written by the <see cref="Save(Stream)"/> method. /// </summary> /// <param name="stream">The stream.</param> /// <returns>The loaded index from the specified stream.</returns> public static VideoSeekIndex Load(Stream stream) { var separator = new[] { ',' }; var trimQuotes = new[] { '"' }; var result = new VideoSeekIndex(null, -1); using (var reader = new StreamReader(stream, Encoding.UTF8, true)) { var state = 0; while (reader.EndOfStream == false) { var line = reader.ReadLine()?.Trim() ?? string.Empty; if (state == 0 && line == SectionHeaderText) { state = 1; continue; } if (state == 1 && line == SectionHeaderFields) { state = 2; continue; } if (state == 2 && !string.IsNullOrWhiteSpace(line)) { var parts = line.Split(separator, 2); if (parts.Length >= 2) { if (int.TryParse(parts[0], out var index)) { result.StreamIndex = index; } result.MediaSource = parts[1] .Trim(trimQuotes) .ReplaceOrdinal("\"\"", "\""); } state = 3; } if (state == 3 && line == SectionDataText) { state = 4; continue; } if (state == 4 && line == SectionDataFields) { state = 5; continue; } if (state == 5 && !string.IsNullOrWhiteSpace(line)) { if (VideoSeekIndexEntry.FromCsvString(line) is VideoSeekIndexEntry entry) { result.Entries.Add(entry); } } } } return(result); }