Пример #1
0
        /// <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);
        }
Пример #2
0
        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;
        }
Пример #4
0
        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;
        }
Пример #5
0
        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);
        }
Пример #6
0
        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));
        }
Пример #7
0
        /// <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;
        }
Пример #10
0
        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;
        }
Пример #12
0
        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;
        }
Пример #13
0
        private TsChunk data;//from parent TsPacket

        internal AdaptationField(TsPacket parent)
        {
            data = parent.data;
        }
Пример #14
0
        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;
        }
Пример #15
0
        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();
        }
Пример #16
0
        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;
        }
Пример #17
0
        /// <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;
        }