public static FlvInfo Read(string Path) { using (FileStream fs = File.OpenRead(Path)) { FlvInfo aFlvInfo = new FlvInfo(); fs.Read(aFlvInfo.Header.Type, 0, aFlvInfo.Header.Type.Length); aFlvInfo.Header.Version = (byte)fs.ReadByte(); aFlvInfo.Header.Stream = (byte)fs.ReadByte(); fs.Read(aFlvInfo.Header.Length, 0, aFlvInfo.Header.Length.Length); byte[] previoustagsize = new byte[4]; while (fs.Read(previoustagsize, 0, previoustagsize.Length) != 0) { FLVTag Tag = new FLVTag(); Tag.PreviousTagSize = previoustagsize; Tag.Type = (byte)fs.ReadByte(); fs.Read(Tag.DataLength, 0, Tag.DataLength.Length); fs.Read(Tag.Time, 0, Tag.Time.Length); Tag.TimeEx = (byte)fs.ReadByte(); fs.Read(Tag.streamsID, 0, Tag.streamsID.Length); byte[] tmp = new byte[4]; tmp[3] = 0; tmp[2] = Tag.DataLength[0]; tmp[1] = Tag.DataLength[1]; tmp[0] = Tag.DataLength[2]; int n = System.BitConverter.ToInt32(tmp, 0); fs.Seek(n, SeekOrigin.Current); aFlvInfo.TagList.Add(Tag); } return(aFlvInfo); } }
private bool ShouldFilterTag(FLVTag tag, TagsFilter filterTags) { if (tag == null) { return(true); } // if the timestamp is lower than the current time if (_currentTime != INVALID_TIME && tag.Timestamp < _currentTime) { tag.Timestamp = _currentTime; //return true; } switch (tag.Type) { case FLVTag.TagType.AUDIO: case FLVTag.TagType.AKAMAI_ENC_AUDIO: return((TagsFilter.AUDIO & filterTags) == 0 || (_alternateTime != INVALID_TIME && tag.Timestamp < _alternateTime)); case FLVTag.TagType.VIDEO: case FLVTag.TagType.AKAMAI_ENC_VIDEO: return((TagsFilter.VIDEO & filterTags) == 0 || (_mediaTime != INVALID_TIME && tag.Timestamp < _mediaTime)); } return(true); }
private void UpdateTimes(FLVTag tag) { if (tag != null) { if (tag is FLVTagAudio) { _alternateTime = tag.Timestamp; } else { _mediaTime = tag.Timestamp; } } }
public FLVTag GetNextTag(Media media, out uint lastTS) { lastTS = 0; FLVTag tag = null; if (FragmentsData[media].Count > 0) { var tagsStore = FragmentsData[media].Peek(); lock (tagsStore) { if (tagsStore.Count > 0) { lastTS = tagsStore.lastTS; tag = tagsStore.Dequeue(); } if (tagsStore.Count < 1 && tagsStore.Complete) { lock (FragmentsData) { FragmentsData[media].Dequeue(); // delete empty TagsStore } } } } return(tag); }
public ParsedContent Read(Stream stream) { var res = new ParsedContent(); var info = new AtomCollection(Channel.ChannelInfo.Extra); var processed = false; var eos = false; while (!eos) { var start_pos = stream.Position; try { switch (state) { case ReaderState.Header: { var bin = ReadBytes(stream, 13); var header = new FileHeader(bin); if (header.IsValid) { Logger.Info("FLV Header found"); fileHeader = header; bin = header.Binary; res.ContentHeader = new Content(position, bin); res.Contents = null; info.SetChanInfoType("FLV"); info.SetChanInfoStreamType("video/x-flv"); info.SetChanInfoStreamExt(".flv"); res.ChannelInfo = new ChannelInfo(info); position = bin.Length; tags.Clear(); state = ReaderState.Body; } else { throw new BadDataException(); } } break; case ReaderState.Body: { var bin = ReadBytes(stream, 11); var read_valid = false; var body = new FLVTag(bin); if (body.IsValidHeader) { body.ReadBody(stream); body.ReadFooter(stream); if (body.IsValidFooter) { read_valid = true; bin = body.Binary; if (res.Contents == null) { res.Contents = new List <Content>(); } res.Contents.Add(new Content(position, bin)); tags.AddLast(new TagDesc { Timestamp = body.Timestamp / 1000.0, DataSize = body.DataSize }); var timespan = tags.Last.Value.Timestamp - tags.First.Value.Timestamp; if (timespan >= 30.0) { var sz = tags.Take(tags.Count - 1).Sum(t => t.DataSize); info.SetChanInfoBitrate((int)(sz * 8 / timespan + 900) / 1000); res.ChannelInfo = new ChannelInfo(info); while (tags.Count > 1) { tags.RemoveFirst(); } } position += bin.Length; } } if (!read_valid) { stream.Position = start_pos; var header = new FileHeader(ReadBytes(stream, 13)); if (header.IsValid) { Logger.Info("New FLV Header found"); read_valid = true; fileHeader = header; bin = header.Binary; res.ContentHeader = new Content(0, bin); res.Contents = null; info.SetChanInfoType("FLV"); info.SetChanInfoStreamType("video/x-flv"); info.SetChanInfoStreamExt(".flv"); res.ChannelInfo = new ChannelInfo(info); tags.Clear(); position = bin.Length; } } if (!read_valid) { throw new BadDataException(); } } break; } processed = true; } catch (EndOfStreamException) { if (!processed) { throw; } stream.Position = start_pos; eos = true; } catch (BadDataException) { stream.Position = start_pos + 1; } } return(res); }
public void DownloadFragment(TagsStore tagsStore) { string fragmentUrl = media.GetFragmentUrl(fragIndex); Program.DebugLog("Fragment Url: " + fragmentUrl); byte[] data = HTTP.TryGETData(fragmentUrl, out int retCode, out string status); int retries = 0; while (retCode >= 500 && retries <= MaxRetriesLoad) { System.Threading.Thread.Sleep(1000); retries++; data = HTTP.TryGETData(fragmentUrl, out retCode, out status); } if (retCode != 200) { string msg = "Download fragment failed " + fragIndex + "/" + media.TotalFragments + " code: " + retCode + " status: " + status; Program.DebugLog(msg); if (Program.verbose) { Program.Message(msg); } if (media.Bootstrap.live) { //media.CurrentFragmentIndex = media.TotalFragments; tagsStore.Complete = true; Done(media); return; } else { throw new InvalidOperationException(status); } } Program.DebugLog("Downloaded: fragment=" + fragIndex + "/" + media.TotalFragments + " lenght: " + data.Length); var boxes = Box.GetBoxes(data); if (boxes.Find(i => i.Type == F4FConstants.BOX_TYPE_MDAT) is MediaDataBox mdat) { lock (tagsStore) { FLVTag.GetVideoAndAudioTags(tagsStore, mdat.data); tagsStore.ARFA = boxes.Find(i => i.Type == F4FConstants.BOX_TYPE_AFRA) as AdobeFragmentRandomAccessBox; tagsStore.Complete = true; } HDSDownloader.LiveIsStalled = false; } else if (media.Bootstrap.live) { HDSDownloader.LiveIsStalled = true; } else { throw new InvalidOperationException("No found mdat box in fragment " + fragIndex + "/" + media.TotalFragments); } if (Program.verbose) { Program.Message(string.Format("Media: {0} Downloaded: {1} Data size: {2}", media.label, fragIndex, data.Length)); } media.CurrentFragmentIndex++; media.Downloaded++; Done(media); }
public async Task ReadAsync( Stream stream, IRTMPContentSink sink, CancellationToken cancel_token) { int len = 0; var bin = new byte[13]; try { len += await stream.ReadBytesAsync(bin, len, 13 - len, cancel_token).ConfigureAwait(false); } catch (EndOfStreamException) { return; } var header = new FLVFileHeader(bin); if (!header.IsValid) { throw new BadDataException(); } sink.OnFLVHeader(header); len = 0; bool eos = false; while (!eos) { try { len += await stream.ReadBytesAsync(bin, len, 11 - len, cancel_token).ConfigureAwait(false); var read_valid = false; var body = new FLVTag(this, bin); if (body.IsValidHeader) { if (await body.ReadTagBodyAsync(stream, cancel_token).ConfigureAwait(false)) { len = 0; read_valid = true; switch (body.Type) { case FLVTag.TagType.Audio: sink.OnAudio(body.ToRTMPMessage()); break; case FLVTag.TagType.Video: sink.OnVideo(body.ToRTMPMessage()); break; case FLVTag.TagType.Script: sink.OnData(new DataAMF0Message(body.ToRTMPMessage())); break; } } } else { len += await stream.ReadBytesAsync(bin, len, 13 - len, cancel_token).ConfigureAwait(false); var new_header = new FLVFileHeader(bin); if (new_header.IsValid) { read_valid = true; sink.OnFLVHeader(header); } } if (!read_valid) { int pos = 1; for (; pos < len; pos++) { var b = bin[pos]; if ((b & 0xC0) == 0 && ((b & 0x1F) == 8 || (b & 0x1F) == 9 || (b & 0x1F) == 18)) { break; } } if (pos == len) { len = 0; } else { Array.Copy(bin, pos, bin, 0, len - pos); len -= pos; } } } catch (EndOfStreamException) { eos = true; } } }
public bool Read(Stream stream, IRTMPContentSink sink) { var processed = false; var eos = false; while (!eos) { retry: var start_pos = stream.Position; try { switch (state) { case ReaderState.Header: { var bin = ReadBytes(stream, 13, out eos); if (eos) { goto error; } var header = new FLVFileHeader(bin); if (header.IsValid) { sink.OnFLVHeader(header); state = ReaderState.Body; } else { throw new BadDataException(); } } break; case ReaderState.Body: { var bin = ReadBytes(stream, 11, out eos); if (eos) { goto error; } var read_valid = false; var body = new FLVTag(this, bin); if (body.IsValidHeader) { if (!body.ReadBody(stream)) { eos = true; goto error; } if (!body.ReadFooter(stream)) { eos = true; goto error; } if (body.IsValidFooter) { read_valid = true; switch (body.Type) { case FLVTag.TagType.Audio: sink.OnAudio(body.ToRTMPMessage()); break; case FLVTag.TagType.Video: sink.OnVideo(body.ToRTMPMessage()); break; case FLVTag.TagType.Script: sink.OnData(new DataAMF0Message(body.ToRTMPMessage())); break; } } } else { stream.Position = start_pos; var headerbin = ReadBytes(stream, 13, out eos); if (eos) { goto error; } var header = new FLVFileHeader(headerbin); if (header.IsValid) { read_valid = true; sink.OnFLVHeader(header); } } if (!read_valid) { stream.Position = start_pos + 1; var b = stream.ReadByte(); while (true) { if (b < 0) { eos = true; goto error; } if ((b & 0xC0) == 0 && ((b & 0x1F) == 8 || (b & 0x1F) == 9 || (b & 0x1F) == 18)) { break; } b = stream.ReadByte(); } stream.Position = stream.Position - 1; goto retry; } } break; } processed = true; } catch (EndOfStreamException) { stream.Position = start_pos; eos = true; } catch (BadDataException) { stream.Position = start_pos + 1; } error: if (eos) { stream.Position = start_pos; eos = true; } } return(processed); }
public static FlvInfo Read(string Path) { using (FileStream fs = File.OpenRead(Path)) { FlvInfo aFlvInfo = new FlvInfo(); fs.Read(aFlvInfo.Header.Type, 0, aFlvInfo.Header.Type.Length); aFlvInfo.Header.Version = (byte)fs.ReadByte(); aFlvInfo.Header.Stream = (byte)fs.ReadByte(); fs.Read(aFlvInfo.Header.Length, 0, aFlvInfo.Header.Length.Length); byte[] previoustagsize = new byte[4]; while (fs.Read(previoustagsize, 0, previoustagsize.Length) != 0) { FLVTag Tag = new FLVTag(); Tag.PreviousTagSize = previoustagsize; Tag.Type = (byte)fs.ReadByte(); fs.Read(Tag.DataLength, 0, Tag.DataLength.Length); fs.Read(Tag.Time, 0, Tag.Time.Length); Tag.TimeEx = (byte)fs.ReadByte(); fs.Read(Tag.streamsID, 0, Tag.streamsID.Length); byte[] tmp = new byte[4]; tmp[3] = 0; tmp[2] = Tag.DataLength[0]; tmp[1] = Tag.DataLength[1]; tmp[0] = Tag.DataLength[2]; int n = System.BitConverter.ToInt32(tmp, 0); fs.Seek(n, SeekOrigin.Current); aFlvInfo.TagList.Add(Tag); } return aFlvInfo; } }
public ParsedContent Read(Stream stream) { var processed = false; var eos = false; while (!eos) { var start_pos = stream.Position; try { switch (state) { case ReaderState.Header: { var bin = ReadBytes(stream, 13); var header = new FileHeader(bin); if (header.IsValid) { Logger.Info("FLV Header found"); contentBuffer.OnStart(); state = ReaderState.Body; } else { throw new BadDataException(); } } break; case ReaderState.Body: { var bin = ReadBytes(stream, 11); var read_valid = false; var body = new FLVTag(bin); if (body.IsValidHeader) { body.ReadBody(stream); body.ReadFooter(stream); if (body.IsValidFooter) { read_valid = true; switch (body.Type) { case FLVTag.TagType.Audio: contentBuffer.OnAudio(body.ToRTMPMessage()); break; case FLVTag.TagType.Video: contentBuffer.OnVideo(body.ToRTMPMessage()); break; case FLVTag.TagType.Script: contentBuffer.OnData(new RTMP.DataAMF0Message(body.ToRTMPMessage())); break; } } } if (!read_valid) { stream.Position = start_pos; var header = new FileHeader(ReadBytes(stream, 13)); if (header.IsValid) { Logger.Info("New FLV Header found"); read_valid = true; contentBuffer.OnStart(); } } if (!read_valid) throw new BadDataException(); } break; } processed = true; } catch (EndOfStreamException) { if (!processed) throw; stream.Position = start_pos; eos = true; } catch (BadDataException) { stream.Position = start_pos+1; } } return contentBuffer.GetContents(); }
public bool Read(Stream stream, IRTMPContentSink sink) { var processed = false; var eos = false; while (!eos) { retry: var start_pos = stream.Position; try { switch (state) { case ReaderState.Header: { var bin = ReadBytes(stream, 13, out eos); if (eos) goto error; var header = new FileHeader(bin); if (header.IsValid) { sink.OnFLVHeader(); state = ReaderState.Body; } else { throw new BadDataException(); } } break; case ReaderState.Body: { var bin = ReadBytes(stream, 11, out eos); if (eos) goto error; var read_valid = false; var body = new FLVTag(this, bin); if (body.IsValidHeader) { if (!body.ReadBody(stream)) { eos = true; goto error; } if (!body.ReadFooter(stream)) { eos = true; goto error; } if (body.IsValidFooter) { read_valid = true; switch (body.Type) { case FLVTag.TagType.Audio: sink.OnAudio(body.ToRTMPMessage()); break; case FLVTag.TagType.Video: sink.OnVideo(body.ToRTMPMessage()); break; case FLVTag.TagType.Script: sink.OnData(new DataAMF0Message(body.ToRTMPMessage())); break; } } } else { stream.Position = start_pos; var headerbin = ReadBytes(stream, 13, out eos); if (eos) goto error; var header = new FileHeader(headerbin); if (header.IsValid) { read_valid = true; sink.OnFLVHeader(); } } if (!read_valid) { stream.Position = start_pos+1; var b = stream.ReadByte(); while (true) { if (b<0) { eos = true; goto error; } if ((b & 0xC0)==0 && ((b & 0x1F)==8 || (b & 0x1F)==9 || (b & 0x1F)==18)) { break; } b = stream.ReadByte(); } stream.Position = stream.Position-1; goto retry; } } break; } processed = true; } catch (EndOfStreamException) { stream.Position = start_pos; eos = true; } catch (BadDataException) { stream.Position = start_pos+1; } error: if (eos) { stream.Position = start_pos; eos = true; } } return processed; }
public ParsedContent Read(Stream stream) { var processed = false; var eos = false; while (!eos) { var start_pos = stream.Position; try { switch (state) { case ReaderState.Header: { var bin = ReadBytes(stream, 13); var header = new FileHeader(bin); if (header.IsValid) { Logger.Info("FLV Header found"); contentBuffer.OnStart(); state = ReaderState.Body; } else { throw new BadDataException(); } } break; case ReaderState.Body: { var bin = ReadBytes(stream, 11); var read_valid = false; var body = new FLVTag(bin); if (body.IsValidHeader) { body.ReadBody(stream); body.ReadFooter(stream); if (body.IsValidFooter) { read_valid = true; switch (body.Type) { case FLVTag.TagType.Audio: contentBuffer.OnAudio(body.ToRTMPMessage()); break; case FLVTag.TagType.Video: contentBuffer.OnVideo(body.ToRTMPMessage()); break; case FLVTag.TagType.Script: contentBuffer.OnData(new RTMP.DataAMF0Message(body.ToRTMPMessage())); break; } } } if (!read_valid) { stream.Position = start_pos; var header = new FileHeader(ReadBytes(stream, 13)); if (header.IsValid) { Logger.Info("New FLV Header found"); read_valid = true; contentBuffer.OnStart(); } } if (!read_valid) { throw new BadDataException(); } } break; } processed = true; } catch (EndOfStreamException) { if (!processed) { throw; } stream.Position = start_pos; eos = true; } catch (BadDataException) { stream.Position = start_pos + 1; } } return(contentBuffer.GetContents()); }
public void StartDownload(string manifestUrl) { GetManifestAndSelectMedia(manifestUrl); Program.Message("Waiting first fragment...\r"); // downloader already running in UpdateBootstrapInfo() DetermineAudioVideoPresentInDownloadedFragment(); var DecoderState = new DecoderLastState(); bool useAltAudio = selectedMediaAlt != null; TagsFilter tagFilter = TagsFilter.ALL; if (UpdateStatusTimer == null && !Program.isRedirected) { UpdateStatusTimer = new Timer(ShowDownloadStatus, null, 0, UpdateStatusInterval); } if (useAltAudio) { tagFilter = TagsFilter.VIDEO; // only video for main media if alternate media is selected } _currentTime = INVALID_TIME; _mediaTime = INVALID_TIME; _alternateTime = INVALID_TIME; droppedAudioFrames = 0; droppedVideoFrames = 0; FLVTag mediaTag = null; FLVTag alternateTag = null; bool needSynchronizationAudio = true; if (!Program.ConsolePresent && Program.isRedirected) { Program.Message("Processing..."); } // --------------- MAIN LOOP DECODE FRAGMENTS ---------------- while (Downloader.TagsAvaliable(selectedMedia) || selectedMedia.Bootstrap.live) { if (mediaTag == null) { mediaTag = Downloader.GetNextTag(selectedMedia); if (mediaTag == null) { Thread.Sleep(100); // for decrease CPU load } } if (useAltAudio && _mediaTime != INVALID_TIME && Downloader.TagsAvaliable(selectedMediaAlt)) { if (alternateTag == null) { alternateTag = Downloader.GetNextTag(selectedMediaAlt); } if (useAltAudio && alternateTag != null && alternateTag.IsAkamaiEncrypted) { if (AD2 == null) // create and init only if need { AD2 = new AkamaiDecryptor(); } AD2.DecryptFLVTag(alternateTag, manifest.baseURL, auth); } if (needSynchronizationAudio && (_mediaTime != INVALID_TIME || _alternateTime != INVALID_TIME)) { uint alternateSynchronizationTime = _alternateTime != INVALID_TIME ? _alternateTime : _mediaTime; alternateTag = Downloader.SeekAudioByTime(selectedMediaAlt, alternateSynchronizationTime); if (alternateTag != null) { needSynchronizationAudio = false; } } } if (mediaTag != null && mediaTag.IsAkamaiEncrypted) { if (AD1 == null) // create and init only if need { AD1 = new AkamaiDecryptor(); } AD1.DecryptFLVTag(mediaTag, manifest.baseURL, auth); } if (useAltAudio && alternateTag != null && alternateTag.IsAkamaiEncrypted) { if (AD2 == null) // create and init only if need { AD2 = new AkamaiDecryptor(); } AD2.DecryptFLVTag(alternateTag, manifest.baseURL, auth); } if (ShouldFilterTag(mediaTag, tagFilter)) { if (mediaTag != null) { if (mediaTag is FLVTagVideo) { droppedVideoFrames++; } totalDroppedFrames++; } mediaTag = null; } else { UpdateTimes(mediaTag); } if (ShouldFilterTag(alternateTag, TagsFilter.AUDIO)) { if (alternateTag != null) { droppedAudioFrames++; totalDroppedFrames++; } alternateTag = null; } else { UpdateTimes(alternateTag); } if (!useAltAudio) { if (mediaTag != null) { _currentTime = mediaTag.Timestamp; FLVFile.Write(mediaTag); mediaTag = null; } } else { if (_mediaTime != INVALID_TIME || _alternateTime != INVALID_TIME) { if (alternateTag != null && (alternateTag.Timestamp >= _currentTime || _currentTime == INVALID_TIME) && (alternateTag.Timestamp <= _mediaTime)) { _currentTime = alternateTag.Timestamp; FLVFile.Write(alternateTag); alternateTag = null; } else if (mediaTag != null && (mediaTag.Timestamp >= _currentTime || _currentTime == INVALID_TIME) && (mediaTag.Timestamp <= _alternateTime)) { _currentTime = mediaTag.Timestamp; FLVFile.Write(mediaTag); mediaTag = null; } } } if ((duration > 0) && (FLVFile.LastTimestamp >= duration)) { Status = "Duration limit reached"; break; } if ((filesize > 0) && (FLVFile.Filesize >= filesize)) { Status = "File size limit reached"; break; } } DestroyUpdateStatusTimer(); ShowDownloadStatus(); }
public static void FixTimestamp(DecoderLastState DecoderState, FLVTag tag) { uint lastTS = DecoderState.prevVideoTS >= DecoderState.prevAudioTS ? DecoderState.prevVideoTS : DecoderState.prevAudioTS; uint fixedTS = lastTS + (uint)fixWindow; if ((DecoderState.baseTS == DecoderLastState.INVALID_TIMESTAMP) && ((tag.Type == FLVTag.TagType.AUDIO) || (tag.Type == FLVTag.TagType.VIDEO))) { DecoderState.baseTS = tag.Timestamp; } if ((DecoderState.baseTS > fixWindow) && (tag.Timestamp >= DecoderState.baseTS)) { tag.Timestamp -= DecoderState.baseTS; } if (lastTS != DecoderLastState.INVALID_TIMESTAMP) { int timeShift = (int)(tag.Timestamp - lastTS); if (timeShift > fixWindow) { Program.DebugLog(string.Format("Timestamp gap detected: PacketTS={0} LastTS={1} Timeshift={2}", tag.Timestamp, lastTS, timeShift)); if (DecoderState.baseTS < tag.Timestamp) { DecoderState.baseTS += (uint)(timeShift - fixWindow); } else { DecoderState.baseTS = (uint)(timeShift - fixWindow); } tag.Timestamp = fixedTS; } else { lastTS = tag.Type == FLVTag.TagType.VIDEO ? DecoderState.prevVideoTS : DecoderState.prevAudioTS; if ((lastTS != DecoderLastState.INVALID_TIMESTAMP) && (int)tag.Timestamp < (lastTS - fixWindow)) { if ((DecoderState.negTS != DecoderLastState.INVALID_TIMESTAMP) && ((tag.Timestamp + DecoderState.negTS) < (lastTS - fixWindow))) { DecoderState.negTS = DecoderLastState.INVALID_TIMESTAMP; } if (DecoderState.negTS == DecoderLastState.INVALID_TIMESTAMP) { DecoderState.negTS = fixedTS - tag.Timestamp; Program.DebugLog(string.Format("Negative timestamp detected: PacketTS={0} LastTS={1} NegativeTS={2}", tag.Timestamp, lastTS, DecoderState.negTS)); tag.Timestamp = (uint)fixedTS; } else { if ((tag.Timestamp + DecoderState.negTS) <= (lastTS + fixWindow)) { tag.Timestamp += (uint)DecoderState.negTS; } else { DecoderState.negTS = fixedTS - tag.Timestamp; Program.DebugLog(string.Format("Negative timestamp override: PacketTS={0} LastTS={1} NegativeTS={2}", tag.Timestamp, lastTS, DecoderState.negTS)); tag.Timestamp = (uint)fixedTS; } } } } } if (tag is FLVTagAudio) { DecoderState.prevAudioTS = tag.Timestamp; } else { DecoderState.prevVideoTS = tag.Timestamp; } }
public async Task ReadAsync( Stream stream, IRTMPContentSink sink, CancellationToken cancel_token) { int len = 0; var bin = new byte[13]; try { len += await stream.ReadBytesAsync(bin, len, 13-len, cancel_token); } catch (EndOfStreamException) { return; } var header = new FileHeader(bin); if (!header.IsValid) throw new BadDataException(); sink.OnFLVHeader(); len = 0; bool eos = false; while (!eos) { try { len += await stream.ReadBytesAsync(bin, len, 11-len, cancel_token); var read_valid = false; var body = new FLVTag(this, bin); if (body.IsValidHeader) { if (await body.ReadTagBodyAsync(stream, cancel_token)) { len = 0; read_valid = true; switch (body.Type) { case FLVTag.TagType.Audio: sink.OnAudio(body.ToRTMPMessage()); break; case FLVTag.TagType.Video: sink.OnVideo(body.ToRTMPMessage()); break; case FLVTag.TagType.Script: sink.OnData(new DataAMF0Message(body.ToRTMPMessage())); break; } } } else { len += await stream.ReadBytesAsync(bin, len, 13-len, cancel_token); var new_header = new FileHeader(bin); if (new_header.IsValid) { read_valid = true; sink.OnFLVHeader(); } } if (!read_valid) { int pos = 1; for (; pos<len; pos++) { var b = bin[pos]; if ((b & 0xC0)==0 && ((b & 0x1F)==8 || (b & 0x1F)==9 || (b & 0x1F)==18)) { break; } } if (pos==len) { len = 0; } else { Array.Copy(bin, pos, bin, 0, len-pos); len -= pos; } } } catch (EndOfStreamException) { eos = true; } } }
public ParsedContent Read(Stream stream) { var res = new ParsedContent(); var info = new AtomCollection(Channel.ChannelInfo.Extra); var processed = false; var eos = false; while (!eos) { var start_pos = stream.Position; try { switch (state) { case ReaderState.Header: { var bin = ReadBytes(stream, 13); var header = new FileHeader(bin); if (header.IsValid) { Logger.Info("FLV Header found"); fileHeader = header; bin = header.Binary; res.ContentHeader = new Content(position, bin); res.Contents = null; info.SetChanInfoType("FLV"); info.SetChanInfoStreamType("video/x-flv"); info.SetChanInfoStreamExt(".flv"); res.ChannelInfo = new ChannelInfo(info); position = bin.Length; tags.Clear(); state = ReaderState.Body; } else { throw new BadDataException(); } } break; case ReaderState.Body: { var bin = ReadBytes(stream, 11); var read_valid = false; var body = new FLVTag(bin); if (body.IsValidHeader) { body.ReadBody(stream); body.ReadFooter(stream); if (body.IsValidFooter) { read_valid = true; bin = body.Binary; if (res.Contents==null) res.Contents = new List<Content>(); res.Contents.Add(new Content(position, bin)); tags.AddLast(new TagDesc { Timestamp=body.Timestamp/1000.0, DataSize=body.DataSize }); var timespan = tags.Last.Value.Timestamp-tags.First.Value.Timestamp; if (timespan>=30.0) { var sz = tags.Take(tags.Count-1).Sum(t => t.DataSize); info.SetChanInfoBitrate((int)(sz*8/timespan+900)/1000); res.ChannelInfo = new ChannelInfo(info); while (tags.Count>1) tags.RemoveFirst(); } position += bin.Length; } } if (!read_valid) { stream.Position = start_pos; var header = new FileHeader(ReadBytes(stream, 13)); if (header.IsValid) { Logger.Info("New FLV Header found"); read_valid = true; fileHeader = header; bin = header.Binary; res.ContentHeader = new Content(0, bin); res.Contents = null; info.SetChanInfoType("FLV"); info.SetChanInfoStreamType("video/x-flv"); info.SetChanInfoStreamExt(".flv"); res.ChannelInfo = new ChannelInfo(info); tags.Clear(); position = bin.Length; } } if (!read_valid) throw new BadDataException(); } break; } processed = true; } catch (EndOfStreamException) { if (!processed) throw; stream.Position = start_pos; eos = true; } catch (BadDataException) { stream.Position = start_pos+1; } } return res; }