/// <summary> /// Writes captions into a text in WebVTT format. /// </summary> /// <param name="captions">Caption blocks to serialize.</param> /// <param name="writer">Text writer to write into.</param> /// <remarks>See http://www.w3.org/TR/webvtt1/ for more details.</remarks> public static Task SerializeAsync( MediaCaptions captions, TextWriter writer) { return(WebVttSerializer.SerializeAsync( WebVttSerializer.GetMediaCaptionBlocks(captions), writer)); }
/// <summary> /// Utility method to return all parts of media captions are a sequence of blocks. /// </summary> /// <param name="captions">Captions to process.</param> /// <returns>Sequence of blocks.</returns> private static IEnumerable <BaseBlock> GetMediaCaptionBlocks( MediaCaptions captions) { if (captions != null) { if (captions.Styles != null && captions.Styles.Length > 0) { foreach (var style in captions.Styles) { if (style != null) { yield return(style); } } } if (captions.Regions != null && captions.Regions.Length > 0) { foreach (var region in captions.Regions) { if (region != null) { yield return(region); } } } if (captions.Cues != null && captions.Cues.Length > 0) { bool needSort = false; Cue previous = null; foreach (var cue in captions.Cues) { if (cue != null) { needSort = previous != null && cue.Start < previous.Start; previous = cue; } if (needSort) { break; } } if (needSort) { var tmp = new List <Cue>(captions.Cues.Length); foreach (var cue in captions.Cues) { if (cue != null) { tmp.Add(cue); } } if (tmp.Count > 0) { tmp.Sort((c1, c2) => c1.Start < c2.Start ? -1 : (c1.Start > c2.Start ? 1 : c1.End.CompareTo(c2.End))); foreach (var cue in tmp) { yield return(cue); } } } else { foreach (var cue in captions.Cues) { yield return(cue); } } } } }
/// <summary> /// Reads WebVTT media captions from a given <see cref="TextReader"/>. /// </summary> /// <param name="reader">Text reader to read the captions.</param> /// <returns>A task that represents the asynchronous read operation.</returns> public static async Task <MediaCaptions> ReadMediaCaptionsAsync( TextReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } // Process stream header line var line = await reader.ReadLineAsync() .ConfigureAwait(false); if (string.IsNullOrWhiteSpace(line) || line.Length < 6 || false == line.StartsWith(Constants.WebVttHeaderToken) || line.Length >= 7 && line[6] != '\t' && line[6] != ' ') { throw new InvalidDataException("The stream does not start with the correct WebVTT file signature."); } var result = new MediaCaptions(); // Process (skip over) optional headers from the stream while (false == string.IsNullOrEmpty(line)) { line = await reader.ReadLineAsync() .ConfigureAwait(false); } // Process media caption blocks. List <RegionDefinition> regions = new List <RegionDefinition>(); List <Style> styles = new List <Style>(); List <Cue> cues = new List <Cue>(); BaseBlock block; do { block = await WebVttParser.ReadBlockAsync(reader) .ConfigureAwait(false); RegionDefinition region = block as RegionDefinition; Style style = block as Style; Cue cue = block as Cue; if (cues.Count == 0) { if (region != null) { regions.Add(region); } else if (style != null) { styles.Add(style); } } else if (region != null || style != null) { throw new InvalidDataException("Region or style blocks cannot be mixed with cue blocks."); } if (cue != null) { cues.Add(cue); } }while (block != null); if (regions.Count > 0) { result.Regions = regions.ToArray(); } if (styles.Count > 0) { result.Styles = styles.ToArray(); } if (cues.Count > 0) { result.Cues = cues.ToArray(); } return(result); }