void HandleKey(SubStreamSegment segment, IEnumerable<ExtKeyTagInstance> extKeys, CancellationToken cancellationToken) { var keys = extKeys.ToArray(); if (keys.Length < 1) return; string keyUri = null; byte[] iv = null; foreach (var key in keys) { var method = key.AttributeObject(ExtKeySupport.AttrMethod); if (string.Equals(MethodNone, method, StringComparison.OrdinalIgnoreCase)) { keyUri = null; continue; } if (!string.Equals(MethodAes, method, StringComparison.OrdinalIgnoreCase)) { if (string.Equals(MethodSampleAes, method, StringComparison.OrdinalIgnoreCase)) throw new NotImplementedException("Method SAMPLE-AES decryption is not implemented"); throw new NotSupportedException("Unknown decryption method type: " + method); } var newUri = key.AttributeObject(ExtKeySupport.AttrUri); if (null != newUri) keyUri = newUri; var newIv = key.AttributeObject(ExtKeySupport.AttrIv); if (null != newIv) iv = newIv; } if (null == keyUri) return; if (null == iv) { iv = new byte[16]; var ms = segment.MediaSequence ?? (_segmentIndex - 1); iv[15] = (byte)(ms & 0xff); iv[14] = (byte)((ms >> 8) & 0xff); iv[13] = (byte)((ms >> 16) & 0xff); iv[12] = (byte)((ms >> 24) & 0xff); } var filter = segment.AsyncStreamFilter; var uri = _parser.ResolveUrl(keyUri); segment.AsyncStreamFilter = async (stream, ct) => { if (null != filter) stream = await filter(stream, ct).ConfigureAwait(false); byte[] key; if (!_keyCache.TryGetValue(uri, out key)) { key = await LoadKeyAsync(uri, cancellationToken).ConfigureAwait(false); if (16 != key.Length) throw new FormatException("AES-128 key length mismatch: " + key.Length); _keyCache[uri] = key; } Debug.WriteLine("Segment AES-128: key {0} iv {1}", BitConverter.ToString(key), BitConverter.ToString(iv)); return _platformServices.Aes128DecryptionFilter(stream, key, iv); }; }
ISegment CreateStreamSegment(M3U8Parser.M3U8Uri uri, CancellationToken cancellationToken) { var url = _parser.ResolveUrl(uri.Uri); var segment = new SubStreamSegment(url, _parser.BaseUrl); if (_mediaSequence.HasValue) segment.MediaSequence = _mediaSequence + _segmentIndex; ++_segmentIndex; var tags = uri.Tags; if (null == tags || 0 == tags.Length) return segment; var info = M3U8Tags.ExtXInf.Find(tags); if (null != info) segment.Duration = TimeSpan.FromSeconds((double)info.Duration); var byteRange = M3U8Tags.ExtXByteRange.Find(tags); if (null != byteRange) HandleByteRange(segment, byteRange); var extKeys = M3U8Tags.ExtXKey.FindAll(tags); if (null != extKeys) HandleKey(segment, extKeys, cancellationToken); return segment; }
void HandleByteRange(SubStreamSegment segment, ByterangeTagInstance byteRange) { if (byteRange.Offset.HasValue) { segment.Offset = byteRange.Offset.Value; _byteRangeOffset = byteRange.Offset.Value; } else segment.Offset = _byteRangeOffset; segment.Length = byteRange.Length; _byteRangeOffset += byteRange.Length; }