/// <summary> /// to push new raw data from any source, pass the data in here /// </summary> /// <param name="data"></param> public bool AddRaw(byte[] data) { //assume it's Mpeg TS for now... var ts = new TsPacket(data); if (!ts.IsValid) { //int i = 0; return(false);//not valid TS packet! } if (data.Length > TsPacket.PacketLength) { var chunk = new TsChunk(data); var packs = chunk.GetTsPackets(); foreach (var p in packs) { if (p.IsValid) { AddTsPacket(p); } } } else { return(AddTsPacket(ts)); } return(true); }
private void CheckCustomPIDs(TsPacket p) { //**TODO: provide a way for users to provide custom/private PIDs //so that the extractor can notify (event or callback) when it sees //one. //throw new NotImplementedException(); }
public PacketizedElementaryStream(TsPacket first) { IsComplete = true;//we assume it is complete until we prove it is not packets = new Queue<TsPacket>(4); packets.Enqueue(first); lastCC = first.ContinuityCounter; payloadIndex = first.PayloadStart; }
public PacketizedElementaryStream(TsPacket first) { IsComplete = true;//we assume it is complete until we prove it is not packets = new Queue <TsPacket>(4); packets.Enqueue(first); lastCC = first.ContinuityCounter; payloadIndex = first.PayloadStart; }
private bool AddTsPacket(TsPacket ts) { if (ts.PID != PID.H264Video) { CheckCustomPIDs(ts); // reclaim buffer bufferPool.Push(ts); return(true);//not video, so ignore it for now, it is a valid packet. } //if (pes == null && ts.IsPayloadUnitStart) // pes = new MpegTS.PacketizedElementaryStream(ts); if (ts.IsPayloadUnitStart && pes != null) { //let's take care of the old (complete) one now: push out buffers //TODO: provide the time stamp/PES with this buffer, or, just provide the //PES? if (pes.IsValid && pes.IsComplete) { //lock (outBuffers) { outBuffers.Enqueue(pes); //SampleCount = outBuffers.Count; } long pts = 0; if (pes.HasPts) { pts = pes.PTS; } OnSampleReady(SampleCount, pts); ++good; } else { ++bad; } pes = new MpegTS.PacketizedElementaryStream(this, ts); //we have the new pes } else if (pes != null) //we have already found the beginning of the stream and are building a pes { pes.Add(ts); } else//looking for a start packet { pes = new PacketizedElementaryStream(this, ts);// } return(true); }
public bool AddPacket(TsPacket ts) { //assume it's Mpeg TS for now... if (!ts.IsValid) { // reclaim buffer if (ts.data.Length == TsPacket.PacketLength) { bufferPool.Push(ts); } return(false);//not valid TS packet! } return(AddTsPacket(ts)); }
/// <summary> /// returns a pooled buffer of length 188 bytes /// </summary> /// <returns></returns> public TsPacket GetBuffer() { TsPacket ret = null; if (bufferPool.Count > 0) { bufferPool.TryPop(out ret); } if (ret == null) { ret = new TsPacket(new byte[TsPacket.PacketLength]); } return(ret); }
/// <summary> /// Add another Ts packet to this stream to be re-built later. /// </summary> /// <param name="next"></param> public void Add(TsPacket next) { packets.Enqueue(next); //check for missed packets if (lastCC < 15 && next.ContinuityCounter != lastCC + 1) { IsComplete = false; } else if (lastCC == 15 && next.ContinuityCounter != 0) { IsComplete = false; } lastCC = next.ContinuityCounter; }
public PacketizedElementaryStream(BufferExtractor extractor, TsPacket first) { if (extractor == null || first == null) { throw new ArgumentNullException("extractor or first", "no ctor parameters may be null"); } myExtractor = extractor; IsComplete = true;//we assume it is complete until we prove it is not packets = new Queue <TsPacket>(4); packets.Enqueue(first); lastCC = first.ContinuityCounter; payloadIndex = first.PayloadStart; }
private TsChunk data;//from parent TsPacket internal AdaptationField(TsPacket parent) { data = parent.data; }
/// <summary> /// Add another Ts packet to this stream to be re-built later. /// </summary> /// <param name="next"></param> public void Add(TsPacket next) { packets.Enqueue(next); //check for missed packets if (lastCC < 15 && next.ContinuityCounter != lastCC + 1) { IsComplete = false; } else if (lastCC == 15 && next.ContinuityCounter != 0) IsComplete = false; lastCC = next.ContinuityCounter; }
protected override async void Run() { try { running = true; var finfo = new System.IO.FileInfo(FilePlayer.SAMPLE);//FilePlayer.dir + "decode.out"); var fs = finfo.OpenRead(); int bytes, count, inIndex = 0; int buffSize = TsPacket.PacketLength * 4;//simulate multiple TS packets grouped into a single UDP packet var buff = new byte[buffSize]; var ts = new MpegTS.TsPacket(buff); buffEx = new BufferExtractor(); //buffEx.SampleReady += BuffEx_SampleReady; bool eof = false; using (info) using (decoder) using (fs) { count = 0; Log.Debug(TAG, "looking for format info"); ////look for the format info. //do //{ // bytes = await fs.ReadAsync(buff, 0, buff.Length).ConfigureAwait(false); // Log.Debug(TAG, "PID: " + string.Format("{0}", ts.PID)); //} while (BitConverter.ToInt32(buff, formatStartI) != formatStartVal); //Log.Debug(TAG, "found format info"); //var tmpB = new byte[23 + 8]; //System.Buffer.BlockCopy(buff, formatStartI - 4, tmpB, 0, tmpB.Length); InitializeDecoder(); fs.Position = 0;//reset sw.Restart(); //bool started = false; do { ++count; try { while (fs.CanRead && buffEx.SampleCount == 0) { if (fs.Length - fs.Position < buffSize) { eof = true; break;//we're @ EOF } //we need a new buffer every loop! buff = new byte[buffSize]; bytes = await fs.ReadAsync(buff, 0, buff.Length) .ConfigureAwait(false); //push the raw data to our custom extractor if (!buffEx.AddRaw(buff)) { Log.Debug("ExtractorActivity, ", " ----------bad TS packet!"); //find next sync byte and try again fs.Position -= buff.Length - buff.ToList().IndexOf(MpegTS.TsPacket.SyncByte); } } if (!fs.CanRead || eof) { break; } } catch (Exception ex) { Log.Error("ExtractorActivity error: ", ex.ToString()); } //get the raw video stream, stripped of Mpeg TS headers var sample = buffEx.DequeueNextSample(); Log.Debug("ExtractorActivity, sampleSize: ", sample.Length.ToString()); //var outputBuffers = decoder.GetOutputBuffers(); //get a input buffer index from the decoder for input inIndex = decoder.DequeueInputBuffer(10000); if (inIndex >= 0) { //get the re-assembled video data from the extractor using (var b = Java.Nio.ByteBuffer.Wrap(sample.Buffer)) { var inB = inputBuffers[inIndex]; //************* //THE BUFFER *******MUST********* be CLEARED before each write, //else when the buffers start getting recycled, the decoder will //read past the end of the current data into old data! //This may cause tearing of the picture, or even a complete //crash of the app from internal errors in native decoder code!!!!! inB.Clear(); inB.Put(b);//put data into the decoder's native buffer //tell the decoder about the new data in the buffer decoder.QueueInputBuffer(inIndex, 0, b.Limit(), 0, MediaCodecBufferFlags.None); }// b.Dispose();//clean up } //else // continue;//we don't have a full video frame, look for more. //check decoder output/state int outIndex = decoder.DequeueOutputBuffer(info, 10000); switch ((Android.Media.MediaCodecInfoState)outIndex) { case MediaCodecInfoState.OutputBuffersChanged: Android.Util.Log.Debug("DecodeActivity", MediaCodecInfoState.OutputBuffersChanged.ToString()); outputBuffers = decoder.GetOutputBuffers(); break; case MediaCodecInfoState.OutputFormatChanged: Android.Util.Log.Debug("DecodeActivity", "New format " + decoder.OutputFormat);//.GetOutputFormat(outIndex)); break; case MediaCodecInfoState.TryAgainLater: Android.Util.Log.Debug("DecodeActivity", "dequeueOutputBuffer timed out!"); break; default: var buffer = outputBuffers[outIndex];// decoder.GetOutputBuffer(outIndex); Android.Util.Log.Verbose("DecodeActivity", "render the buffer, " + buffer); //bool gcDone = false; // We use a very simple clock to keep the video FPS, or the video // playback will be too fast //This causes the next frame to not be rendered too quickly. while (info.PresentationTimeUs / 1000 > sw.ElapsedMilliseconds) { await Task.Delay(10).ConfigureAwait(false); } //the decoder won't advance without this... //must be called before the next decoder.dequeue call decoder.ReleaseOutputBuffer(outIndex, true); break; } } while (fs.CanRead && running); Log.Debug("DecodeActivity", MediaCodecBufferFlags.EndOfStream.ToString()); try { decoder.QueueInputBuffer(inIndex, 0, 0, 0, MediaCodecBufferFlags.EndOfStream); } catch (Exception ex) { Log.Debug("DecodeActivity", "error closing decoder!"); } }//dispose filestream,decoder, info } catch (Exception ex) { Log.Debug(this.GetType().Name, ex.ToString()); } info = null; decoder = null; }
protected override async void Run() { try { running = true; var finfo = new System.IO.FileInfo(FilePlayer.SAMPLE);//FilePlayer.dir + "decode.out"); var fs = finfo.OpenRead(); int bytes, count, inIndex =0; int buffSize = TsPacket.PacketLength*4;//simulate multiple TS packets grouped into a single UDP packet var buff = new byte[buffSize]; var ts = new MpegTS.TsPacket(buff); buffEx = new BufferExtractor(); //buffEx.SampleReady += BuffEx_SampleReady; bool eof = false; using(info) using(decoder) using (fs) { count = 0; Log.Debug(TAG, "looking for format info"); ////look for the format info. //do //{ // bytes = await fs.ReadAsync(buff, 0, buff.Length).ConfigureAwait(false); // Log.Debug(TAG, "PID: " + string.Format("{0}", ts.PID)); //} while (BitConverter.ToInt32(buff, formatStartI) != formatStartVal); //Log.Debug(TAG, "found format info"); //var tmpB = new byte[23 + 8]; //System.Buffer.BlockCopy(buff, formatStartI - 4, tmpB, 0, tmpB.Length); InitializeDecoder(); fs.Position = 0;//reset sw.Restart(); //bool started = false; do { ++count; try { while (fs.CanRead && buffEx.SampleCount == 0) { if (fs.Length - fs.Position < buffSize) { eof = true; break;//we're @ EOF } //we need a new buffer every loop! buff = new byte[buffSize]; bytes = await fs.ReadAsync(buff, 0, buff.Length) .ConfigureAwait(false); //push the raw data to our custom extractor if (!buffEx.AddRaw(buff)) { Log.Debug("ExtractorActivity, ", " ----------bad TS packet!"); //find next sync byte and try again fs.Position -= buff.Length - buff.ToList().IndexOf(MpegTS.TsPacket.SyncByte); } } if (!fs.CanRead || eof) break; } catch (Exception ex) { Log.Error("ExtractorActivity error: ", ex.ToString()); } //get the raw video stream, stripped of Mpeg TS headers var sample = buffEx.DequeueNextSample(); Log.Debug("ExtractorActivity, sampleSize: ", sample.Length.ToString()); //var outputBuffers = decoder.GetOutputBuffers(); //get a input buffer index from the decoder for input inIndex = decoder.DequeueInputBuffer(10000); if (inIndex >= 0) { //get the re-assembled video data from the extractor using (var b = Java.Nio.ByteBuffer.Wrap(sample.Buffer)) { var inB = inputBuffers[inIndex]; //************* //THE BUFFER *******MUST********* be CLEARED before each write, //else when the buffers start getting recycled, the decoder will //read past the end of the current data into old data! //This may cause tearing of the picture, or even a complete //crash of the app from internal errors in native decoder code!!!!! inB.Clear(); inB.Put(b);//put data into the decoder's native buffer //tell the decoder about the new data in the buffer decoder.QueueInputBuffer(inIndex, 0, b.Limit(), 0, MediaCodecBufferFlags.None); }// b.Dispose();//clean up } //else // continue;//we don't have a full video frame, look for more. //check decoder output/state int outIndex = decoder.DequeueOutputBuffer(info, 10000); switch ((Android.Media.MediaCodecInfoState)outIndex) { case MediaCodecInfoState.OutputBuffersChanged: Android.Util.Log.Debug("DecodeActivity", MediaCodecInfoState.OutputBuffersChanged.ToString()); outputBuffers = decoder.GetOutputBuffers(); break; case MediaCodecInfoState.OutputFormatChanged: Android.Util.Log.Debug("DecodeActivity", "New format " + decoder.OutputFormat);//.GetOutputFormat(outIndex)); break; case MediaCodecInfoState.TryAgainLater: Android.Util.Log.Debug("DecodeActivity", "dequeueOutputBuffer timed out!"); break; default: var buffer = outputBuffers[outIndex];// decoder.GetOutputBuffer(outIndex); Android.Util.Log.Verbose("DecodeActivity", "render the buffer, " + buffer); //bool gcDone = false; // We use a very simple clock to keep the video FPS, or the video // playback will be too fast //This causes the next frame to not be rendered too quickly. while (info.PresentationTimeUs / 1000 > sw.ElapsedMilliseconds) { await Task.Delay(10).ConfigureAwait(false); } //the decoder won't advance without this... //must be called before the next decoder.dequeue call decoder.ReleaseOutputBuffer(outIndex, true); break; } } while (fs.CanRead && running); Log.Debug("DecodeActivity", MediaCodecBufferFlags.EndOfStream.ToString()); try { decoder.QueueInputBuffer(inIndex, 0, 0, 0, MediaCodecBufferFlags.EndOfStream); } catch (Exception ex) { Log.Debug("DecodeActivity", "error closing decoder!"); } }//dispose filestream,decoder, info } catch (Exception ex) { Log.Debug(this.GetType().Name, ex.ToString()); } info = null; decoder = null; }
private bool AddTsPacket(TsPacket ts) { if (ts.PID != PID.H264Video) { CheckCustomPIDs(ts); return true;//not video, so ignore it for now, it is a valid packet. } //if (pes == null && ts.IsPayloadUnitStart) // pes = new MpegTS.PacketizedElementaryStream(ts); if (ts.IsPayloadUnitStart && pes != null) { //let's take care of the old (complete) one now: push out buffers //TODO: provide the time stamp/PES with this buffer, or, just provide the //PES? if (pes.IsValid && pes.IsComplete) { lock (outBuffers) { outBuffers.Enqueue(pes); SampleCount = outBuffers.Count; } long pts = 0; if (pes.HasPts) pts = pes.PTS; OnSampleReady(SampleCount, pts); ++good; } else ++bad; pes = new MpegTS.PacketizedElementaryStream(ts);//we have the new pes } else if (pes != null)//we have already found the beginning of the stream and are building a pes { pes.Add(ts); } else//looking for a start packet pes = new PacketizedElementaryStream(ts);// return true; }
/// <summary> /// to push new raw data from any source, pass the data in here /// </summary> /// <param name="data"></param> public bool AddRaw(byte[] data) { //assume it's Mpeg TS for now... var ts = new TsPacket(data); if (!ts.IsValid) { //int i = 0; return false;//not valid TS packet! } if (data.Length > TsPacket.PacketLength) { var chunk = new TsChunk(data); var packs = chunk.GetTsPackets(); foreach (var p in packs) if(p.IsValid) AddTsPacket(p); } else return AddTsPacket(ts); return true; }