Example #1
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;
        }